P3285 [SCOI2014]方伯伯的OJ
阿新 • • 發佈:2020-11-21
連結
因為 \(n \leq 10^8\),\(m \leq 10^5\),所以可以用一個域很大的權值線段樹動態開點維護。
開始 \(L=1\),\(R=n\),\([L,R]\) 的點值看作 \(1\),把一個位置的數提前相當於 \(L-1\) 的位置加 \(1\),原來的位置 \(1\) 變為 \(0\),放後也類似。
用兩個 \(map\) 維護數的位置和編號的相互對映。
#include<bits/stdc++.h> #define IL inline #define LL long long using namespace std; const int N=1e5+3,inf=1e8+1e5+10; int n,m,ans,L,R,rt; map<int,int>mp1,mp2; IL int in(){ char c;int f=1; while((c=getchar())<'0'||c>'9') if(c=='-') f=-1; int x=c-'0'; while((c=getchar())>='0'&&c<='9') x=x*10+c-'0'; return x*f; } struct hh{ int cnt,ls[N*400],rs[N*400],sum[N*400]; void upd(int &o,int l,int r,int u){ if(!o) o=++cnt;++sum[o]; if(l==r) return; int mid=l+r>>1; if(u<=mid) upd(ls[o],l,mid,u); else upd(rs[o],mid+1,r,u); } int ask(int o,int l,int r,int rr){ if(!o) return 0; if(r<=rr) return sum[o]; int mid=l+r>>1; if(rr<=mid) return ask(ls[o],l,mid,rr); return ask(ls[o],l,mid,rr)+ask(rs[o],mid+1,r,rr); } int kth(int o,int l,int r,int k){ if(l==r) return l; int mid=l+r>>1,res=max(0,min(R,mid)-max(L,l)+1)-sum[ls[o]]; if(res>=k) return kth(ls[o],l,mid,k); return kth(rs[o],mid+1,r,k-res); } }T; int query(int x){ if(mp1.find(x)!=mp1.end()) x=mp1[x]; return x-L-T.ask(rt,-inf,inf,x-1)+1; } void work1(int x,int y){ if(mp1.find(x)!=mp1.end()) mp2[mp1[x]]=y,mp1[y]=mp1[x]; else mp2[x]=y,mp1[y]=x; printf("%d\n",ans=query(y)); } void work2(int x){ printf("%d\n",ans=query(x));int y=x; if(mp1.find(x)!=mp1.end()) x=mp1[x]; T.upd(rt,-inf,inf,x),mp1[y]=--L,mp2[L]=y; } void work3(int x){ printf("%d\n",ans=query(x));int y=x; if(mp1.find(x)!=mp1.end()) x=mp1[x]; T.upd(rt,-inf,inf,x),mp1[y]=++R,mp2[R]=y; } void work4(int k){ int x=T.kth(rt,-inf,inf,k); if(mp2.find(x)!=mp2.end()) printf("%d\n",ans=mp2[x]); else printf("%d\n",ans=x); } int main() { int op,x,y; n=in(),m=in(),L=1,R=n; for(int i=1;i<=m;++i){ op=in(),x=in()-ans; if(op==1) work1(x,in()-ans); else if(op==2) work2(x); else if(op==3) work3(x); else work4(x); } return 0; }