【Codeforces 631C 】Report(单调栈,思维模拟)
題干:
Each month Blake gets the report containing main economic indicators of the company "Blake Technologies". There are?n?commodities produced by the company. For each of them there is exactly one integer in the final report, that denotes corresponding revenue. Before the report gets to Blake, it passes through the hands of?m?managers. Each of them may reorder the elements in some order. Namely, the?i-th manager either sorts first?ri?numbers in non-descending or non-ascending order and then passes the report to the manager?i?+?1, or directly to Blake (if this manager has number?i?=?m).
Employees of the "Blake Technologies" are preparing the report right now. You know the initial sequence?ai?of length?n?and the description of each manager, that is value?ri?and his favourite order. You are asked to speed up the process and determine how the final report will look like.
Input
The first line of the input contains two integers?n?and?m?(1?≤?n,?m?≤?200?000)?— the number of commodities in the report and the number of managers, respectively.
The second line contains?n?integers?ai?(|ai|?≤?109)?— the initial report before it gets to the first manager.
Then follow?m?lines with the descriptions of the operations managers are going to perform. The?i-th of these lines contains two integers?ti?and?ri?(,?1?≤?ri?≤?n), meaning that the?i-th manager sorts the first?ri?numbers either in the non-descending (if?ti?=?1) or non-ascending (if?ti?=?2) order.
Output
Print?n?integers?— the final report, which will be passed to Blake by manager number?m.
Examples
Input
3 1 1 2 3 2 2Output
2 1 3Input
4 2 1 2 4 3 2 3 1 2Output
2 4 1 3Note
In the first sample, the initial report looked like:?1 2 3. After the first manager the first two numbers were transposed:?2 1?3. The report got to Blake in this form.
In the second sample the original report was like this:?1 2 4 3. After the first manager the report changed to:?4 2 1?3. After the second manager the report changed to:?2 4?1 3. This report was handed over to Blake.
題目大意:
給定n個數和m次操作。每次操作分兩種輸入格式:?
1? ?xi?。表示將前xi個數升序排列。
2? ?xi 。表示將前xi個數降序排列。
讓你輸出操作完以后的序列。
解題報告:
? ? ? 首先對于不同位置的操作,顯然對于第i個操作,若有第j個操作(1<=j<i)(1<=j<i) 且(xj<=xi)(xj<=xi),則第j個操作是可以無視的。這樣我們就維護一個xi嚴格遞減的單調棧,在兩個鄰近操作之間倒著填數就可以了,因為這些操作的特性就是,最左邊的數字確定不了,但是右側的數字一定是確定的,,最后一個操作單獨處理(全填上就可以了)
?
超時代碼1:(這個是又改過一點了?忘了答案正確與否了,直接從電腦上貼過來了)(確定了,這個是WA的)
#include<bits/stdc++.h>using namespace std; int a[200000 + 5]; int op[200000 + 5],zxz[200000 + 5],R[200000 + 5],zz[200000 + 5]; int n,m,top; bool cmp(const int & x,const int & y) {return x>y; } int main() {scanf("%d%d",&n,&m);int maxx = 0,maxi = 1;for(int i = 1; i<=n; i++) scanf("%d",a+i);for(int i = 1; i<=m; i++) {scanf("%d%d",op+i,zxz+i);if(zxz[i] > maxx) {maxx = zxz[i];maxi = i;} }stack<int > sk;for(int i = 1; i<=m; i++) {while(!sk.empty() && zxz[sk.top()] < zxz[i]) sk.pop();if(sk.empty()) R[i] = 0;else R[sk.top()] = i;sk.push(i);}while(maxi !=0 ) {zz[++top] = maxi;maxi = R[maxi];} // printf("%d %d \n%d %d \n",zz[1],zz[2],zxz[zz[1]],zxz[zz[2]]);if(op[zz[top]] == 1) sort(a+1,a+zxz[zz[top]] + 1);else sort(a+1,a+zxz[zz[top]]+1,cmp);for(int i = top-1; i>=1; i--) {if(op[zz[i]] == 1) {sort(a+zxz[zz[i+1]],a + zxz[zz[i]] + 1);}else {sort(a+zxz[zz[i+1]],a + zxz[zz[i]] + 1,cmp);}} // for(int i = 1; i<=m; i++) printf("%d %d\n",i,R[i]);for(int i = 1; i<=n; i++) {printf("%d%c",a[i],i == n ? '\n' : ' ');}return 0 ; }真*超時代碼:(思路十分清晰的超時代碼)
#include<bits/stdc++.h>using namespace std; int a[200000 + 5]; int op[200000 + 5],zxz[200000 + 5],R[200000 + 5]; int n,m; bool cmp(int x,int y) {return x>y; } int main() {while(~scanf("%d%d",&n,&m)) {int maxx = 0,maxi = 1;for(int i = 1; i<=n; i++) scanf("%d",a+i);for(int i = 1; i<=m; i++) {scanf("%d%d",op+i,zxz+i);if(zxz[i] > maxx) {maxx = zxz[i];maxi = i;} }stack<int > sk;for(int i = 1; i<=m; i++) {while(!sk.empty() && zxz[sk.top()] < zxz[i]) sk.pop();if(sk.empty()) R[i] = 0;else R[sk.top()] = i;sk.push(i);}while(maxi !=0 ) {if(op[maxi] == 1) {sort(a+1,a + zxz[maxi] + 1);}else {sort(a+1,a+zxz[maxi]+1,cmp);}maxi = R[maxi];} // for(int i = 1; i<=m; i++) printf("%d %d\n",i,R[i]);for(int i = 1; i<=n; i++) {printf("%d%c",a[i],i == n ? '\n' : ' ');}}return 0 ;}AC代碼:(202ms)
#include<bits/stdc++.h>using namespace std; int a[200000 + 5],b[200000 + 5]; int op[200000 + 5],zxz[200000 + 5],R[200000 + 5],zz[200000 + 5]; int n,m,top; bool cmp(const int & x,const int & y) {return x>y; } int main() {scanf("%d%d",&n,&m);int maxx = 0,maxi = 1;for(int i = 1; i<=n; i++) scanf("%d",a+i);for(int i = 1; i<=m; i++) {scanf("%d%d",op+i,zxz+i);if(zxz[i] > maxx) {maxx = zxz[i];maxi = i;} }stack<int > sk;//右側臨近比他小的中 最大的 for(int i = 1; i<=m; i++) {while(!sk.empty() && zxz[sk.top()] < zxz[i]) sk.pop();if(sk.empty()) R[i] = 0;else R[sk.top()] = i;sk.push(i);}while(maxi !=0 ) {zz[++top] = maxi;maxi = R[maxi];}if(op[zz[1]] == 1) sort(a+1,a+zxz[zz[1]] + 1);else sort(a+1,a+zxz[zz[1]]+1,cmp);for(int i = 1; i<=zxz[zz[1]]; i++) {b[i] = a[i];//先從小到大保存下來,最后輸出a就可以了 } sort(b+1,b+zxz[zz[1]]+1);//從小到大 即我們需要填入這些數進入a數組中 int l = 1,r = zxz[zz[1]];for(int i = 1; i<top; i++) {for(int j = zxz[zz[i]]; j>=zxz[zz[i+1]]+1; j--) {if(op[zz[i]] == 1) a[j] = b[r--];else a[j] = b[l++];}}for(int j = zxz[zz[top]]; j>=1; j--) {if(op[zz[top]] == 1) a[j] = b[r--];else a[j] = b[l++];}for(int i = 1; i<=n; i++) {printf("%d%c",a[i],i == n ? '\n' : ' ');}return 0 ; }幫助我們深刻理解一下單調棧中存的元素的性質!!其實可以不用while那一步來存一個zz,,直接可以用棧內的元素其實就是我們想要的。
另外我們寫的這個單調棧還是有點講究的啊。。寫成了R數組中存的是不嚴格小于的了、、、這樣還是會有重復操作的,。,改成嚴格小于的應該會好一些?還沒提交試一下、、、(試過了,WA15了,想想也確實不能這么寫, 因為就是得不嚴格小于,也就是小于等于,因為你想啊,萬一后面還有一個和你一樣大的,那肯定選后面那個不選你啊,因為你這個操作肯定會被后面那個操作覆蓋掉的。。。)
附:簡潔的30行代碼:(紅名大佬Orz,不過思路還是可以學習一下的)(187ms)
#include<bits/stdc++.h> #define ll long long using namespace std; int n,m,maxx,x; int main() {scanf("%d%d",&n,&m);vector<int> a, b(n + 2, 0), c(n + 2, 0);for(int i = 0; i<n; i++) {scanf("%d",&x);a.push_back(x);//或者直接讀入cin>>a[i]; }for(int i = 1; i<=m; i++) {int x, y;scanf("%d%d", &x, &y);b[y - 1] = x;//操作 c[y - 1] = i;//操作數maxx = max(maxx, y);}vector<int> tmp = a, ans = a;sort(tmp.begin(),tmp.begin() + maxx);int l = 0, r = maxx - 1;for(int i = maxx - 1; i >= 0; i--) {if(c[i] < c[i + 1]) {c[i] = c[i + 1];b[i] = b[i + 1];}}for(int i = maxx - 1; i >= 0; i--) {if(b[i] == 2) ans[i] = tmp[l++];else ans[i] = tmp[r--];}for(int i = 0; i < n; ++i)printf("%d ", ans[i]);return 0; }改成了數組的形式還是187ms:
#include<bits/stdc++.h> #define ll long long using namespace std; int n,m,maxx,x; int a[200000 + 5],b[200000 + 5],c[200000 + 5],tmp[200000 + 5],ans[200000 + 5]; int main() {scanf("%d%d",&n,&m);for(int i = 0; i<n; i++) {scanf("%d",a+i);}for(int i = 1; i<=m; i++) {int x, y;scanf("%d%d", &x, &y);b[y - 1] = x;//操作 c[y - 1] = i;//操作數maxx = max(maxx, y);}for(int i = 0; i<n; i++) {ans[i] = tmp[i] = a[i];} // vector<int> tmp = a, ans = a;sort(tmp,tmp+maxx);int l = 0, r = maxx - 1;for(int i = maxx - 1; i >= 0; i--) {if(c[i] < c[i + 1]) {c[i] = c[i + 1];b[i] = b[i + 1];}}for(int i = maxx - 1; i >= 0; i--) {if(b[i] == 2) ans[i] = tmp[l++];else ans[i] = tmp[r--];}for(int i = 0; i < n; ++i)printf("%d ", ans[i]);return 0; }?
總結
以上是生活随笔為你收集整理的【Codeforces 631C 】Report(单调栈,思维模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【POJ - 1463】Strategi
- 下一篇: 公开报道首例:曝岚图FREE街头起火