bzoj3224 splay板子
开始学习新知识: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(int fa;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; } } }