洛谷P3369 普通disco 非旋treap
阿新 • • 發佈:2018-12-12
為了上篇博文服務的 程式碼在這 嘻嘻
/* P 3369 */ #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <algorithm> #include <map> #include <set> #include <sstream> #include <cstring> #include <iostream> 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[B]) {ch[A][1] = Merge(ch[A][1],B);update(A);return A;}//如果rnd[l]<rnd[r],我們就保留第一棵樹的左子樹,另一棵樹作為它的右子樹; else {ch[B][0] = Merge(A,ch[B][0]);update(B);return B;} //如果rnd[l]>=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; }