P3369
为了上篇博文服务的 代码在这 嘻嘻
/* P 3369 */ #include #include #include #include #include #include #include #include #include #include using namespace std; const int MAX_N = 500010; int siz[MAX_N],ch[MAX_N][2],rnd[MAX_N],val[MAX_N]; int T,cnt,m,x,y,z,p,a,root,com; int read(){ int x= 0,f = 1;char c= getchar(); while(c>'9'||c<'0') {if(c=='-') f = -1;c = getchar();} while(c>='0'&&c<='9') {x = x*10+ c-'0';c = getchar();} return x*f; } void update(int x){ siz[x] = 1 + siz[ch[x][0]] + siz[ch[x][1]]; } int Insert(int a){ siz[++cnt] = 1; val[cnt] = a; rnd[cnt] = rand(); return cnt; } int Merge(int A,int B){ if(!A||!B) return A+B; if(rnd[A]=rnd[r],那我们可以保留第二棵树的右子树,另一颗树作为它的左子树。 } void split(int now,int k,int &x,int &y){ if(!now) x = y = 0;//第一次x和y要为0 后来会回溯不会影响 else { if(val[now]<=k) {x = now;split(ch[now][1],k,ch[now][1],y);}//我们遍历到一个节点时,如果它的权值小于k,那么它的左子树会被分到左边的树里,然后我们遍历它的右儿子, else {y = now;split(ch[now][0],k,x,ch[now][0]);}//如果大于k,则把它的右子树分到右边的树里,遍历左儿子。 update(now); } } void spilt(int now,int k,int &x,int &y){//排名分裂 if(!now) x = y = 0; else { if(k<=siz[ch[now][0]]){ y = now; split(ch[now][0],k,x,ch[now][0]); } else { x = now; split(ch[now][1],k-siz[ch[now][0]] - 1,ch[now][1],y); } update(now); } } int kth(int now,int k){ while(1){ if(k<=siz[ch[now][0]]) now = ch[now][0]; else if(k==siz[ch[now][0]]+1) return now; else k-=siz[ch[now][0]]+1,now=ch[now][1]; } } void del(int a){//删除:删除权值为v的点,先把整颗树以v为权值split成两棵树a,b,再把a树按照v-1分成c,d。这时候值为v的点一定为d的根,那么我们把d的两个子儿子merge起来 split(root,a,x,z); split(x,a-1,x,y); y = Merge(ch[y][0],ch[y][1]); root = Merge(Merge(x,y),z); } int Getrank(int root,int a){//直接按照a-1的权值把树分开,那么x树中最大的应该小于等于a-1,那么a的排名就是size[x]+1 split(root,a-1,x,y); int res = siz[x] + 1; root = Merge(x,y); return res; } int getpre(int a){ split(root,a-1,x,y); int res = val[kth(x,siz[x])]; root = Merge(x,y); return res; } int getnext(int a){ split(root,a,x,y); int res = val[kth(y,1)]; root = Merge(x,y); return res; } int main(){ int n = read(); int opt; for(int i = 1;i<=n;++i){ opt = read(); int a; a = read(); if(opt==1){ split(root,a,x,y); root = Merge(Merge(x,Insert(a)),y); } else if(opt==2){ del(a); } else if(opt==3){ printf("%d\n",Getrank(root,a)); } else if(opt==4){ printf("%d\n",val[kth(root,a)]); } else if(opt==5){ printf("%d\n",getpre(a)); } else{ printf("%d\n",getnext(a)); } } return 0; }