bzoj3224 splay板子
阿新 • • 發佈:2018-11-19
開始學習新知識:splay——tree
是個板子題,學習splay可以看部落格
https://blog.csdn.net/Clove_unique/article/details/50630280
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define MAXN 1000000 int ch[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],key[MAXN]; int sz,root; inline void clear(int x){ ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0; } inline bool get(int x){ return ch[f[x]][1]==x; } inline void update(int x){//更新結點x的size if(x){ size[x]=cnt[x]; if(ch[x][0]) size[x]+=size[ch[x][0]]; if(ch[x][1]) size[x]+=size[ch[x][1]]; } } inline void rotate(int x){//一次旋轉//得到x的父親,爺爺,是不是左子樹 int old=f[x],oldf=f[old],whichx=get(x); ch[old][whichx]=ch[x][whichx^1]; f[ch[old][whichx]]=old; ch[x][whichx^1]=old;f[old]=x; f[x]=oldf; if(oldf) ch[oldf][ch[oldf][1]==old]=x; update(old);update(x);//不要忘記更新size } inline void splay(int x){ for(intfa;fa=f[x];rotate(x))//再把x翻上來 if(f[fa])//如果fa非根,且x和fa是同一側,那麼先翻轉fa,否則先翻轉x rotate((get(x)==get(fa))?fa:x); root=x;//最後把x設為root } inline void insert(int x){ if(root==0){//插到空樹裡 sz++;ch[sz][0]=ch[sz][1]=f[sz]=0; root=sz;size[sz]=cnt[sz]=1;key[sz]=x; return; } int now=root,fa=0; while(1){//不斷往下尋找直到找到對應值 if(x==key[now]){ cnt[now]++;update(now);update(fa); splay(now);break;//把now置頂 } fa=now; now=ch[now][key[now]<x];//往下搜尋x if(now==0){//新建結點 sz++;ch[sz][0]=ch[sz][1]=0; f[sz]=fa; size[sz]=cnt[sz]=1; ch[fa][key[fa]<x]=sz; key[sz]=x; update(fa); splay(sz);//把sz置頂 break; } } } inline int find(int x){//尋找x所在位置(排名) int now=root,ans=0; while(1){ if(x<key[now])//往左子樹搜尋 now=ch[now][0]; else { ans+=(ch[now][0]?size[ch[now][0]]:0); //找到對應的鍵值,置頂now,返回 if(x==key[now]){splay(now);return ans+1;} ans+=cnt[now]; now=ch[now][1];//往右子樹 } } } inline int findx(int x){//找第x名的值 int now=root; while(1){ if(ch[now][0] && x<=size[ch[now][0]]) now=ch[now][0];//往左子樹搜尋 else { int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];// if(x<=temp) return key[now]; x-=temp;now=ch[now][1];//往右子樹搜尋 } } } inline int pre(){//前驅即左子樹裡的最大值 int now=ch[root][0]; while(ch[now][1]) now=ch[now][1]; return now; } inline int next(){//後繼是右子樹裡的最小值 int now=ch[root][1]; while(ch[now][0]) now=ch[now][0]; return now; } inline void del(int x){ int whatever=find(x);//只是把x置頂 //x的個數>1 if(cnt[root]>1){cnt[root]--;update(root);return;} //單個x if(!ch[root][0] && !ch[root][1]){clear(root);root=0;return;} //只有左子樹或者只有右子樹 if(!ch[root][0]){//刪掉根,右兒子做根 int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return; } if(!ch[root][1]){ int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return; } //前驅作為根(前驅是沒有右兒子的),右子樹掛到前驅的右子樹,刪掉根 else { int pree=pre(),oldroot=root; splay(pree); ch[root][1]=ch[oldroot][1]; f[ch[oldroot][1]]=pree; clear(oldroot); update(pree); } } int main(){ int n,op,x; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&op,&x); switch(op){ case 1:insert(x);break; case 2:del(x);break; case 3:printf("%d\n",find(x));break; case 4:printf("%d\n",findx(x));break; case 5:insert(x);printf("%d\n",key[pre()]);del(x);break; case 6:insert(x);printf("%d\n",key[next()]);del(x);break; } } }