暑假第二场积分赛————F题

组下标从1开始的数组s,进行q次操作:考虑两种操作:
1 r,将子序列a[1] 到a[r] 从小到大排序
2 r,将子序列a[1] 到a[r] 从大到小排序

输入
第一行输入T组数据T (1 ≤ T ≤ 10)
第一行输入两个数字n, q(1 ≤ n, q ≤ 1e4)
第二行包含n个整数ai(−1e9 ≤ ai ≤ 1e9) —初始序列
然后q行表示m个操作. 第i行包含两个整数op(1 ≤ op ≤ 2), r(1 ≤ r ≤ n)

输出
输出n个数字,即数组被操作q次改变后的数组
注意,我们要输出的是最终改变后的结果

输入样例
2
3 1
1 2 3
2 2
4 2
1 2 4 3
2 3
1 2

输出样例
2 1 3
2 4 1 3

HINT
在第二组样例中初始序列是: 1 2 4 3.
执行第一次操作后的序列是: 4 2 1 3. 执行第二次操作后的序列是: 2 4 1 3.

分析题意可得,这组序列的最终结果一定是r值最大的那一个以及在它后面的那些比它小的r值导致的,这样就有了思路

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cstdlib>

using namespace std;
const int maxn = 1e5 + 20;
int re[maxn];//用来储存r值最大的那一部分在初始时的数组
int ans[maxn];//用来储存最终答案数组
int in[maxn];//初始输入数组
int s2[maxn], s[maxn];//分别记录r和op

int main()
{
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		memset(re, 0, sizeof(re));
		memset(in, 0, sizeof(in));
		memset(s2, 0, sizeof(s2));
		memset(s, 0, sizeof(s));
		int n, m;
		cin >> n >> m;
		for (int i = 1; i <=n; i++) scanf("%d", &in[i]);
		int tt = 1;
		s2[0] = 1e6;
		for (int i = 0; i < m; i++)//如果你输入的r值比前面的r值大的话,tt指针后退找到比你当前r值大的r值,然后从它开始重新输入
		{
			int a1, a2;
			scanf("%d%d", &a1, &a2);
			while (a2 >=s2[tt - 1]) tt--;
			s2[tt] = a2, s[tt] = a1, tt++;
		}
		for (int i = s2[1]+1; i <= n; i++)  ans[i] = in[i];//因为r值后的数组不受影响所以直接读入就好
		for (int i = 1; i <= s2[1]; i++)
			re[i] = in[i];
		sort(re + 1, re + 1 + s2[1]);//先排序;
		int uu = 1, kk = s2[1];
		for (int i = 1; i <= m; i++)
		{
			if (s[i] == 1)//如果当前顺序要求是升序,那么按着re数组的顺序读入就好,一直读到下一个顺序,所以是从后面往前输入
			{
				for (int j = s[i]; j >s[i + 1]; j--) ans[j] = re[kk--];
			}
			else 
			{
				for (int j = s[i]; j > s[i + 1]; j--)
					ans[j] = re[uu++];
			}
		}
		for (int i = 1; i < n; i++) printf("%d ", ans[i]);
		printf("%d\n", ans[n]);
	}
	system("pause");
	return	0;
}

猜你喜欢

转载自blog.csdn.net/qq_41670466/article/details/81429739
今日推荐