CF631C Report
Link
Solution
注意到每次排序的 是一个前缀。而若先排一个较短的前缀,之后又排一 个大点的前缀,那么显然这个小的会被覆盖,等价于没有排序。将所有这样的无用排序删除,最终会得到一个长度严格单调下降的操作序列(可以用单调栈维护)。考虑栈内相邻的两个操作,前缀长度分别为 \(x\)、\(y\),且 \(x<y\),那么中间的 \(x-y\) 个数一定是确定的。可以发现其一定是连续的一段最大值或最小值(因为是排序),所以可以用优先队列维护。
#include<stdio.h>
#include<queue>
using namespace std;
#define N 200007
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
struct Op{
int op,x;
}sta[N];
struct Node1{
int x,pos;
bool operator <(const Node1 &X) const{return x<X.x;}
};
struct Node2{
int x,pos;
bool operator <(const Node2 &X) const{return x>X.x;}
};
bool vis[N];
int n,m,top=0,a[N],ans[N];
priority_queue<Node1> Q1;
priority_queue<Node2> Q2;
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
Op t;
for(int i=1;i<=m;i++){
t.op=read(),t.x=read();
while(top&&t.x>=sta[top].x) top--;
sta[++top]=t;
}
for(int i=n;i>sta[1].x;i--) ans[i]=a[i];
for(int i=1;i<=sta[1].x;i++)
Q1.push((Node1){a[i],i}),Q2.push((Node2){a[i],i});
int pos=1;
for(int i=sta[1].x;i;i--){
if(pos<top&&i<=sta[pos+1].x) pos++;
if(sta[pos].op==1){
while(!Q1.empty()&&vis[Q1.top().pos]) Q1.pop();
Node1 now=Q1.top(); Q1.pop();
vis[now.pos]=1,ans[i]=now.x;
}else{
while(!Q2.empty()&&vis[Q2.top().pos]) Q2.pop();
Node2 now=Q2.top(); Q2.pop();
vis[now.pos]=1,ans[i]=now.x;
}
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}