又一道好題

題目鏈接

戳我

\(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("");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章