洛谷P3285/LOJ2212/BZOJ3595[SCOI2014]方伯伯的OJ(线段树)
不会维护区间的Splay QAQ。题目n这么大,直接维护是肯定不行的,考虑维护区间内删去的点,那么减一下就是区间内原有的点,可以解决第k大和排名,至于按编号检索,用两个map维护编号和线段树位置之间的关系,修改时维护一下即可。
#include<cstdio> #include<map> using namespace std; const int N=100050; char rB[1<<21],*rS,*rT,wB[1<<21]; int wp=-1; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;} inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;} inline void pc(char c){if(wp+1==(1<<21))flush();wB[++wp]=c;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } short buf[15]; inline void wt(int x){ short l=-1; while(x>9){ buf[++l]=x%10; x/=10; } pc(x|48); while(l>=0)pc(buf[l--]|48); pc('\n'); } int cnt[N<<5],lc[N<<5],rc[N<<5],sz=1,rt=1,lft,rgt; map<int,int> pos,id; inline int Max(int a,int b){return a>b?a:b;} inline int Min(int a,int b){return a<b?a:b;} inline int pid(int x){return id.find(x)==id.end()?x:id[x];} inline int idp(int x){return pos.find(x)==pos.end()?x:pos[x];} void add(int &o,int L,int R,int x){ if(!o)o=++sz; ++cnt[o]; if(L<R){ int M=L+R>>1; if(x<=M)add(lc[o],L,M,x); else add(rc[o],M+1,R,x); } } int kth(int o,int L,int R,int k){ if(L==R)return pid(L); int M=L+R>>1,s=Max(0,Min(M,rgt)-Max(L,lft)+1-cnt[lc[o]]); return k<=s?kth(lc[o],L,M,k):kth(rc[o],M+1,R,k-s); } int rnk(int o,int L,int R,int x){ if(!cnt[o]||L==R)return 0; int M=L+R>>1; if(x<=M)return rnk(lc[o],L,M,x); return cnt[lc[o]]+rnk(rc[o],M+1,R,x); } int main(){ int n=rd(),m=rd(),t,x,y,p,lans=0,tL=1-m,tR=n+m,res; lft=1;rgt=n; while(m--){ t=rd();x=rd()-lans; if(t==4)wt(lans=kth(rt,tL,tR,x)); else{ p=idp(x); wt(res=p-lft+1-rnk(rt,tL,tR,p)); if(t==2){ pos[x]=--lft;id[lft]=x; add(rt,tL,tR,p); }else if(t==3){ pos[x]=++rgt;id[rgt]=x; add(rt,tL,tR,p); }else{pos[id[p]=y=rd()-lans]=p;} lans=res; } } flush(); return 0; }