splay完整模板:
#include<iostream> #include<cstdio> #include<climits> #include<algorithm> #include<cmath> #include<cstring> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) const int M=1e5+10; int son[M][2],siz[M],cnt[M],fa[M],key[M],root; bool getf(int x){//查询当前节点是父亲节点的左儿子还是右儿子 return son[fa[x]][1]==x; } void update(int x){//更新节点的siz值(即子树大小) siz[x]=cnt[x]; if(son[x][0])siz[x]+=siz[son[x][0]]; if(son[x][1])siz[x]+=siz[son[x][1]]; } void rotate(int x){//旋转 int f=fa[x],ff=fa[f]; bool d=getf(x),dd=getf(f); son[f][d]=son[x][!d];fa[son[f][d]]=f; son[x][!d]=f;fa[f]=x; fa[x]=ff;son[ff][dd]=x; update(x); update(f); } void splay(int x,int goal){//将某个节点旋转到目标节点的儿子处 while(fa[x]!=goal){ int f=fa[x],ff=fa[f]; if(ff!=goal)rotate(getf(f)==getf(x)?f:x); rotate(x); } if(goal==0)root=x; } int tot=0; void insert(int x){//插入一个数 if(root==0){ int t=++tot; fa[t]=0;cnt[t]=siz[t]=1;son[t][0]=son[t][1]=0; key[t]=x; root=t; return; } int u=root; while(1){ if(key[u]==x){ cnt[u]++;siz[u]++; return; } if(x<key[u]){ if(son[u][0])siz[u]++,u=son[u][0]; else{ int t=++tot; son[u][0]=t; key[t]=x;cnt[t]=siz[t]=1;siz[u]++; son[t][0]=son[t][1]=0; fa[t]=u; splay(t,0); return; } } else{ if(son[u][1])siz[u]++,u=son[u][1]; else{ int t=++tot; son[u][1]=t; key[t]=x;cnt[t]=siz[t]=1;siz[u]++; son[t][0]=son[t][1]=0; fa[t]=u; splay(t,0); return; } } } } int query_rank(int x){//查询x的排名 int u=root,ans=0; while(1){ if(key[u]==x){ if(son[u][0])ans+=siz[son[u][0]]; return ans+1; } if(x<key[u])u=son[u][0]; else{ if(son[u][0])ans+=siz[son[u][0]]; ans+=cnt[u];u=son[u][1]; } } } int find_rank(int x){//查询排名为x的数 int u=root; while(1){ int y=son[u][0]?siz[son[u][0]]:0; if(x<=y)u=son[u][0]; else if(x>y+cnt[u])x-=siz[son[u][0]]+cnt[u],u=son[u][1]; else return key[u]; } } int Find(int x){//查找数x的位置 int u=root; while(1){ if(key[u]==x)return u; if(x<key[u])u=son[u][0]; else u=son[u][1]; } } int pre(int x){//返回中序遍历中某个节点的前驱节点(先splay到根) splay(Find(x),0); int u=son[root][0]; while(son[u][1])u=son[u][1]; return u; } int query_pre(int x){//查询x的前驱(小于x的最大值) int u=root,MAX; while(1){ if(key[u]>=x){ if(son[u][0])u=son[u][0]; else return MAX; } else{ MAX=key[u]; if(son[u][1])u=son[u][1];else return MAX; } } } int query_next(int x){//查询x的后继(大于x的最小值) int u=root,MIN; while(1){ if(key[u]<=x){ if(son[u][1])u=son[u][1]; else return MIN; } else{ MIN=key[u]; if(son[u][0])u=son[u][0];else return MIN; } } } void del(int x){//删除数x(有多个只删除其中一个) int u=Find(x); splay(u,0); if(cnt[u]>1){ cnt[u]--;siz[u]--; return; } if(!son[root][0]&&!son[root][1])root=0; else if(!son[root][0])root=son[root][1],fa[root]=0; else if(!son[root][1])root=son[root][0],fa[root]=0; else{ int newroot=pre(x),oldroot=root; splay(newroot,0); son[root][1]=son[oldroot][1]; fa[son[root][1]]=root; update(root); } } int main(){ int n;scanf("%d",&n); while(n--){ int opt,x; scanf("%d%d",&opt,&x); if(opt==1)insert(x); else if(opt==2)del(x); else if(opt==3)printf("%d\n",query_rank(x)); else if(opt==4)printf("%d\n",find_rank(x)); else if(opt==5)printf("%d\n",query_pre(x)); else printf("%d\n",query_next(x)); } return 0; }
平衡树的应用——区间翻转:
#include<iostream> #include<cstdio> #include<cstring> #include<climits> #include<algorithm> #include<cmath> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) const int M=1e5+10; int son[M][2]={0},fa[M],siz[M],cnt[M],key[M]; int n,m,root; bool tag[M]={0}; void clear(int x){ son[x][0]=son[x][1]=fa[x]=siz[x]=cnt[x]=0; } bool getf(int x){ return son[fa[x]][1]==x; } void update(int x){ siz[x]=cnt[x]; if(son[x][0])siz[x]+=siz[son[x][0]]; if(son[x][1])siz[x]+=siz[son[x][1]]; } void rotate(int x){ int f=fa[x],ff=fa[f];bool d=getf(x); son[f][d]=son[x][!d];fa[son[x][!d]]=f; son[x][!d]=f;fa[f]=x; son[ff][son[ff][1]==f]=x;fa[x]=ff; update(f);update(x); } void splay(int x,int goal){//将x旋转到目标位置 while(fa[x]!=goal){ int f=fa[x],ff=fa[f]; if(ff!=goal)rotate(getf(x)==getf(f)?f:x); rotate(x); } if(goal==0)root=x; } int tot=0; void build(int l,int r,int f,int g){//构造完美平衡树 int t=++tot; son[f][g]=t;fa[t]=f;cnt[t]=1; int mid=(l+r)>>1;key[t]=mid; if(l==r){ siz[t]=1; return; } if(l<mid)build(l,mid-1,t,0); if(mid<r)build(mid+1,r,t,1); update(t); } void pushdown(int u){ if(son[u][0])tag[son[u][0]]^=1; if(son[u][1])tag[son[u][1]]^=1; tag[u]=0;swap(son[u][0],son[u][1]); } int Find(int x){ int u=root; while(1){ if(tag[u])pushdown(u); if(siz[son[u][0]]==x-1){ //cout<<key[u]; return u; } if(siz[son[u][0]]<x-1)x-=siz[son[u][0]]+1,u=son[u][1]; else u=son[u][0]; } } void print(int x){//按中序遍历打印平衡树 if(tag[x])pushdown(x); if(son[x][0])print(son[x][0]); if(key[x]&&key[x]<=n)printf("%d ",key[x]); if(son[x][1])print(son[x][1]); } int main(){ scanf("%d%d",&n,&m); build(0,n+1,0,0);root=1; while(m--){ int l,r;scanf("%d%d",&l,&r); l=Find(l);r=Find(r+2); splay(l,0);splay(r,l); tag[son[son[root][1]][0]]^=1;//翻转区间时在子树的根上打标记 //print(root); } print(root); }