CF631C Report

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]);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/14124626.html