又一道好题

题目链接

戳我

\(Solution\)

维护一个上升的序列,对于一个操作把\(x+1\),不会使得这个序列下降,对于操作1,假设x下标位置的值是\(a\),把他和最右边数值为\(a\)的点交换一个位置再\(+1\)同样也不会影响这个序列的单调性。所以搞一个树状数组区间加单点查询即可,对于交换操作记录一下原序列座标在树状数组的下标和树状数组的下标在原数组中表示的下标即可。

操作二搞两个数组记录一下对于某个数\(x\)最左边和最右边的位置即可,然后随便搞搞就过了。

\(code\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
	while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
	return f*x;
}
int b[300010],a[300010],c[300010];
int L[300010],R[300010];
int Ans[300010],n,q;
int lowbit(int x){
    return x&(-x);
}
void Add(int x,int c){
    while(x>0)
        a[x]+=c,x-=lowbit(x);
} 
int sum(int x){
    int ans=0;
   // cout<<x,exit(0);
    while(x<=n)
        ans+=a[x],x+=lowbit(x);
    return ans;
}
void add(int x,int y){
    Add(y,1);
    Add(x-1,-1);
}
signed main(){
    int T=read();
    while(T--){
        n=read(),q=read();
        for(int i=1;i<=n;i++)
            c[i]=b[i]=i,a[i]=0,L[i]=0,R[i]=0;
        R[0]=n,L[0]=1;
        while(q--){
            int op=read(),x=read();
            if(op==2){
                int l=L[x],r=R[x];
                add(l,r);
                //cout<<sum(1)<<" ";
                if(!L[x+1]) L[x+1]=L[x],R[x+1]=R[x];
                else L[x+1]=L[x];
                L[x]=R[x]=0;
            } else{
                int now=sum(b[x]);
                int r=R[now],k=c[r];
                int Now=b[x];
                c[Now]=k,c[r]=x;
                b[x]=r,b[k]=Now;
                add(r,r);
                if(L[now]==R[now])
                    L[now]=0,R[now]=0;
                else R[now]--;
                if(!L[now+1]) L[now+1]=r,R[now+1]=r;
                else L[now+1]=r;
            }
        }
        for(int i=1;i<=n;i++)
            Ans[c[i]]=sum(i);
        for(int i=1;i<=n;i++) cout<<Ans[i]<<" ";
        puts("");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章