题意:给长度为n的序列,操作次数为m;n and m (1 ≤ n, m ≤ 200 000) ,操作分为t r,当t = 1时表示将[1,r]序列按非递减排序,t = 2时表示将序列[1,r]按非递增排序;输出m次操作后的序列?
思路:由于排序是前缀排序,那么前面的操作ti,ri;如果 ri <= rj;那么第i次操作直接被覆盖了。这样我们可以知道有用的排序操作ri是按照严格递减的;并且这时在ri 与r(i + 1)之间的数与后面的操作无关了~~(线性处理),这就直接说明了只需要排序一次,即对于[1,max(ri)]排序,之后直接用双指针在排好序的数组中找到对应的值填到结果数组中即可;
#include<bits/stdc++.h> using namespace std; typedef __int64 ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} const int N = 200200; int a[N],b[N],t[N],r[N],p[N],q[N]; int main() { int n,m; read2(n,m); for(int i = 1;i <= n;i++) read1(a[i]),b[i] = a[i]; for(int i = 1;i <= m;i++) read2(t[i],r[i]); int mx = 0, cnt = 0; for(int i = m;i >= 1; i--){//逆序增加mx;压缩出有用的排序即可; if(r[i] > mx) mx = r[i],p[++cnt] = r[i],q[cnt] = t[i]; } p[0] = 0;//完全处理; sort(b + 1,b + mx + 1);//a最终排序的元素在b中找即可; int la = 1, ra = mx, lb = 1,rb = mx; for(int i = cnt;i > 0;i--){ if(q[i] == 1) for(;ra > p[i - 1];ra--,rb--) a[ra] = b[rb]; else for(;ra > p[i - 1];ra--,lb++) a[ra] = b[lb]; } for(int i = 1;i <= n;i++) printf("%d ",a[i]); return 0; }
时间: 2024-10-19 11:43:00