【Codeforces 631C 】Report(单调栈,思维模拟)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/82813478

题干:

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 2

Output

2 1 3 

Input

4 2
1 2 4 3
2 3
1 2

Output

2 4 1 3 

Note

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;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/82813478