从普通平衡树到可持久化平衡树
这篇只是一个模板,没有写讲解,写得不好,别看!
-
普通平衡树
-
操作分别为
- 插入 x数
- 删除 x 数(若有多个相同的数,因只删除一个)
- 查询 x 数的排名(排名定义为比当前数小的数的个数 +1 )
- 查询排名为 x 的数
- 求 x 的前驱(前驱定义为小于 x,且最大的数)
- 求 x的后继(后继定义为大于 x,且最小的数)
-
Splay版本(为了防止特殊数据,添加了随机换根操作)
-
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<set> #define maxn 100005 #define lson son[now][0] #define rson son[now][1] using namespace std; set<int> s; int n,root,tot; int son[maxn][2],fa[maxn],val[maxn],siz[maxn]; void pushup(int now) { siz[now]=siz[lson]+siz[rson]+1; } void rotate(int x,int &k) { int y=fa[x],z=fa[y],l,r; l=son[y][1]==x;r=l^1; if(y==k) k=x; else {if(son[z][0]==y) son[z][0]=x;else son[z][1]=x;} fa[x]=z;fa[y]=x;fa[son[x][r]]=y; son[y][l]=son[x][r];son[x][r]=y; pushup(y);pushup(x); } void splay(int x,int &k) { while(x!=k) { int y=fa[x],z=fa[y]; //cout<<"fuck "<<x<<' '<<y<<" "<<k<<endl; if(y!=k) { if((son[y][0]==x)^(son[z][0]==y)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int cnt; void insert(int &now,int v,int last) { //cnt++; if(!now) { now=++tot; s.insert(tot); val[tot]=v; fa[now]=last; splay(tot,root); int temp=rand()%tot+1; if(s.find(temp)!=s.end()) splay(temp,root); cnt=0; return; } if(v<=val[now]) insert(lson,v,now); else insert(rson,v,now); } void del(int v) { int pos=root; while(val[pos]!=v) pos=son[pos][val[pos]<v]; splay(pos,root); s.erase(pos); int now=son[pos][1],flag; if(!now) { flag=1; now=son[pos][0]; if(!now) { fa[pos]=0; val[pos]=0; root=0; return; } } else flag=0; while(son[now][flag]) now=son[now][flag]; int t=root;splay(now,root); son[now][flag]=son[t][flag];fa[son[t][flag]]=now;fa[now]=0; pushup(now); } int getrank(int v) { cnt=0; int now=root,ans=0; while(now) { cnt++; if(v>val[now]) {ans+=siz[lson]+1;now=rson;} else now=lson; } //cerr<<"its "<<cnt<<endl; return ans+1; } int find(int v) { int now=root; while(now) { if(siz[lson]+1==v) return val[now]; else if(siz[lson]+1>v) now=lson; else v-=(siz[lson]+1),now=rson; } return val[now]; } int suf(int v) { int now=root,ans; while(now) { if(val[now]<v){ans=val[now];now=rson;} else now=lson; } return ans; } int nex(int v) { int now=root,ans; while(now) { if(val[now]<=v) now=rson; else {ans=val[now];now=lson;} } return ans; } int main() { scanf("%d",&n); while(n--) { int op,x; scanf("%d%d",&op,&x); if(op==1) insert(root,x,0); if(op==2) del(x); if(op==3) printf("%d\n",getrank(x)); if(op==4) printf("%d\n",find(x)); if(op==5) printf("%d\n",suf(x)); if(op==6) printf("%d\n",nex(x)); } }
-
-
Treap版本(好写)
-
#include<stdio.h> #include<string.h> #include<stdlib.h> #define maxn 100005 #define lson son[now][0] #define rson son[now][1] #define min(a,b) ((a)<(b) ? (a):(b)) #define max(a,b) ((a)>(b) ? (a):(b)) const int inf=2e9+5; typedef struct nod { int first,second; } nod; int root,tot,sz[maxn]; int son[maxn][2],val[maxn],k[maxn]; void pushup(int now) { sz[now]=sz[lson]+sz[rson]+1; } int merge(int x,int y) { if(!x || !y) return x+y; if(k[x]<k[y]) return son[x][1]=merge(son[x][1],y),pushup(x),x; else return son[y][0]=merge(x,son[y][0]),pushup(y),y; } nod split(int now,int v) { if(!now) { nod temp; temp.first=0; temp.second=0; return temp; } nod y; if(sz[lson]>=v) { y=split(lson,v); lson=y.second; pushup(now); y.second=now; } else { y=split(rson,v-sz[lson]-1); rson=y.first; pushup(now); y.first=now; } return y; } int find(int v) { nod x=split(root,v-1),y=split(x.second,1); int ans=y.first; root=merge(merge(x.first,ans),y.second); return val[ans]; } int rk(int now,int v) { int minn=inf,maxx=0; while(now) { if(val[now]==v) minn=min(minn,maxx+sz[lson]+1); if(v>val[now]) maxx+=sz[lson]+1,now=rson; else now=lson; } return minn==inf ? maxx : minn; } void insert(int v) { int pos=rk(root,v); nod x=split(root,pos); sz[++tot]=1; val[tot]=v; k[tot]=rand(); root=merge(merge(x.first,tot),x.second); } void del(int v) { int pos=rk(root,v); nod x=split(root,pos-1),y=split(x.second,1); root=merge(x.first,y.second); } int suc(int v) { int now=root,ans=inf; while(now) { if(val[now]>v) { ans=min(ans,val[now]); now=lson; } else now=rson; } return ans; } int pre(int v) { int now=root,ans=-inf; while(now) { if(val[now]<v) { ans=max(ans,val[now]); now=rson; } else now=lson; } return ans; } int main() { int _; scanf("%d",&_); while(_--) { int op,x; scanf("%d%d",&op,&x); if(op==1) insert(x); if(op==2) del(x); if(op==3) printf("%d\n",rk(root,x)); if(op==4) printf("%d\n",find(x)); if(op==5) printf("%d\n",pre(x)); if(op==6) printf("%d\n",suc(x)); } return 0; }
-
-
-
文艺平衡树
-
集成区间赋值和翻转的Splay
-
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #define inf 1000000000 #define maxn 1000005 using namespace std; int n,m,root,cnt; queue<int>q; bool tag[maxn],rev[maxn]; int fa[maxn],id[maxn],a[maxn],son[maxn][2]; int sum[maxn],siz[maxn],v[maxn],maxx[maxn],lx[maxn],rx[maxn]; void pushup(int now) { int lson=son[now][0],rson=son[now][1]; sum[now]=sum[lson]+sum[rson]+v[now]; siz[now]=siz[lson]+siz[rson]+1; maxx[now]=max(maxx[lson],maxx[rson]); maxx[now]=max(maxx[now],lx[rson]+v[now]+rx[lson]); lx[now]=max(lx[lson],sum[lson]+v[now]+lx[rson]); rx[now]=max(rx[rson],sum[rson]+v[now]+rx[lson]); } void pushdown(int now) { int lson=son[now][0],rson=son[now][1]; if(tag[now]) { tag[now]=rev[now]=0; if(lson) tag[lson]=1,v[lson]=v[now],sum[lson]=v[now]*siz[lson]; if(rson) tag[rson]=1,v[rson]=v[now],sum[rson]=v[now]*siz[rson]; if(v[now]>=0) { if(lson) lx[lson]=rx[lson]=maxx[lson]=sum[lson]; if(rson) lx[rson]=rx[rson]=maxx[rson]=sum[rson]; } else { if(lson) lx[lson]=rx[lson]=0,maxx[lson]=v[now]; if(rson) lx[rson]=rx[rson]=0,maxx[rson]=v[now]; } } if(rev[now]) { rev[now]^=1;rev[lson]^=1;rev[rson]^=1; swap(lx[lson],rx[lson]);swap(lx[rson],rx[rson]); swap(son[lson][0],son[lson][1]);swap(son[rson][0],son[rson][1]); } } void rotate(int x,int &k) { int y=fa[x],z=fa[y],l,r; l=(son[y][1]==x);r=l^1; if(y==k) k=x; else son[z][son[z][1]==y]=x; fa[son[x][r]]=y;fa[y]=x;fa[x]=z; son[y][l]=son[x][r];son[x][r]=y; pushup(y);pushup(x);//顺序千万不能错 } void splay(int x,int &k) { while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) { if((son[y][0]==x)^(son[z][0]==y)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int now,int rk) { pushdown(now); int lson=son[now][0],rson=son[now][1]; if(siz[lson]+1==rk) return now; if(siz[lson]>=rk) return find(lson,rk); return find(rson,rk-siz[lson]-1); } void set(int now) { if(!now) return; int lson=son[now][0],rson=son[now][1]; set(lson);set(rson);q.push(now);//一定要记住push now fa[now]=son[now][0]=son[now][1]=0; tag[now]=rev[now]=0; return; } int split(int now,int tot) { int x=find(root,now),y=find(root,now+tot+1); splay(x,root);splay(y,son[x][1]); return son[y][0]; } void query(int now,int tot) { int x=split(now,tot); printf("%d\n",sum[x]); } void modify(int now,int tot,int val) { int x=split(now,tot),y=fa[x]; tag[x]=1;v[x]=val;sum[x]=val*siz[x]; if(val>=0) lx[x]=rx[x]=maxx[x]=sum[x]; else lx[x]=rx[x]=0,maxx[x]=val; pushup(y);pushup(fa[y]);//pushup 一定要记清 } void reverse(int now,int tot) { int x=split(now,tot),y=fa[x]; if(!tag[x]) { rev[x]^=1; swap(son[x][0],son[x][1]); swap(lx[x],rx[x]); pushup(y);pushup(fa[y]); } } void erase(int now,int tot) { int x=split(now,tot),y=fa[x]; set(x);son[y][0]=0; pushup(y);pushup(fa[y]); } void build(int l,int r,int flag) { if(l>r) return; int mid=(l+r)>>1,now=id[mid],last=id[flag]; if(l==r) { sum[now]=a[l]; siz[now]=1; tag[now]=rev[now]=0; if(a[l]>0) lx[now]=rx[now]=maxx[now]=a[l]; else lx[now]=rx[now]=0,maxx[now]=a[l]; } else build(l,mid-1,mid),build(mid+1,r,mid); v[now]=a[mid];fa[now]=last;pushup(now); son[last][mid>=flag]=now; } void insert(int now,int tot) { for(int i=1;i<=tot;i++) scanf("%d",&a[i]); for(int i=1;i<=tot;i++) { if(!q.empty()) id[i]=q.front(),q.pop(); else id[i]=++cnt; } build(1,tot,0); int z=id[(1+tot)>>1]; int x=find(root,now+1),y=find(root,now+2); splay(x,root);splay(y,son[x][1]); fa[z]=y;son[y][0]=z; pushup(y);pushup(x); } void out(int now) { pushdown(now); int lson=son[now][0],rson=son[now][1]; if(lson) out(lson); if(2<=now && now<=n+1) printf("%d ",now-1); if(rson) out(rson); } int main() { scanf("%d%d",&n,&m); maxx[0]=a[1]=a[n+2]=-inf; for(int i=1;i<=n;i++)a[i+1]=i;; for(int i=1;i<=n+2;i++)id[i]=i; build(1,n+2,0); root=(n+3)>>1;cnt=n+2; while(m--) { int l,r; scanf("%d%d",&l,&r); reverse(l,r-l+1); } out(root); }
-
-
Treap(简单好写)
-
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #define maxn 100005 #define lson (son[now][0]) #define rson (son[now][1]) #define mid ((nl+nr)>>1) using namespace std; int n,m,root; int fa[maxn],son[maxn][2],sz[maxn],rev[maxn]; void pushup(int now) { sz[now]=sz[lson]+sz[rson]+1; } void pushdown(int now) { if(rev[now]) { swap(lson,rson); rev[lson]^=1; rev[rson]^=1; rev[now]^=1; } } void build(int nl,int nr,int pa) { if(nl>nr) return; if(nl==nr) { sz[nl]=1; fa[nl]=pa; son[pa][nl>pa]=nl; return; } build(nl,mid-1,mid); build(mid+1,nr,mid); fa[mid]=pa; son[pa][mid>pa]=mid; pushup(mid); } void rotate(int x,int &k) { int y=fa[x],z=fa[y]; int l=(son[y][1]==x),r=l^1; if(y==k) k=x; else { if(son[z][0]==y) son[z][0]=x; else son[z][1]=x; } fa[x]=z; fa[son[x][r]]=y; fa[y]=x; son[y][l]=son[x][r]; son[x][r]=y; pushup(y); pushup(x); } void splay(int x,int &k) { while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) { int _=0; if((son[z][0]==y) ^_^ (son[y][0]==x)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int now,int v) { // cerr<<now<<" "<<v<<endl; pushdown(now); if(sz[lson]+1==v) return now; if(sz[lson]+1<v) return find(rson,v-(sz[lson]+1)); return find(lson,v); } void reverse(int l,int r) { l=find(root,l); r=find(root,r+2); splay(l,root); splay(r,son[l][1]); rev[son[r][0]]^=1; } int main() { scanf("%d%d",&n,&m); build(1,n+2,0); root=((1+(n+2))>>1); for(int i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); reverse(l,r); } for(int i=2;i<=n+1;i++) printf("%d ",find(root,i)-1); }
-
-
-
可持久化平衡树
-
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
-
只能用Treap了
-
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> #define maxn 500005*60 #define lson son[now][0] #define rson son[now][1] using namespace std; const int inf=2147483647; typedef pair<int,int> pr; int root[maxn],tot,sz[maxn],cnt; int son[maxn][2],val[maxn],k[maxn]; void pushup(int now) { sz[now]=sz[lson]+sz[rson]+1; } int copy(int now) { tot++; sz[tot]=sz[now]; son[tot][0]=son[now][0]; son[tot][1]=son[now][1]; val[tot]=val[now]; k[tot]=k[now]; return tot; } int merge(int x,int y) { if(!x || !y) return x+y; if(k[x]<k[y]) return son[x][1]=merge(son[x][1],y),pushup(x),x; else return son[y][0]=merge(x,son[y][0]),pushup(y),y; } pr split(int now,int v) { if(!now) return pr(0,0); pr y; if(sz[lson]>=v) { int x=copy(now); y=split(lson,v); son[x][0]=y.second; pushup(x); y.second=x; } else { int x=copy(now); y=split(rson,v-sz[lson]-1); son[x][1]=y.first; pushup(x); y.first=x; } return y; } int find(int ver,int v,int p) { pr x=split(root[ver],v-1),y=split(x.second,1); int ans=y.first; if(p==0) root[ver]=merge(merge(x.first,ans),y.second); else root[++cnt]=merge(merge(x.first,ans),y.second); return val[ans]; } int rk(int now,int v) { int minn=inf,maxx=0; while(now) { if(val[now]==v) minn=min(minn,maxx+sz[lson]+1); if(v>val[now]) maxx+=sz[lson]+1,now=rson; else now=lson; } return minn==inf ? maxx+1 : minn; } int insrk(int now,int v) { int minn=inf,maxx=0; while(now) { if(val[now]==v) minn=min(minn,maxx+sz[lson]+1); if(v>val[now]) maxx+=sz[lson]+1,now=rson; else now=lson; } return minn==inf ? maxx : minn; } void insert(int ver,int v) { int pos=insrk(root[ver],v); pr x=split(root[ver],pos); sz[++tot]=1; val[tot]=v; k[tot]=rand(); root[++cnt]=merge(merge(x.first,tot),x.second); } void del(int ver,int v) { int pos=rk(root[ver],v); if(find(ver,pos,0)!=v) { root[++cnt]=root[ver]; return; } pr x=split(root[ver],pos-1),y=split(x.second,1); root[++cnt]=merge(x.first,y.second); } int suc(int ver,int v) { int now=root[ver],ans=inf; while(now) { if(val[now]>v) { ans=min(ans,val[now]); now=lson; } else now=rson; } cnt++; root[cnt]=root[ver]; return ans; } int pre(int ver,int v) { int now=root[ver],ans=-inf; while(now) { if(val[now]<v) { ans=max(ans,val[now]); now=rson; } else now=lson; } cnt++; root[cnt]=root[ver]; return ans; } int main() { int _; scanf("%d",&_); while(_--) { int ver,op,x; scanf("%d%d%d",&ver,&op,&x); if(op==1) insert(ver,x); if(op==2) del(ver,x); if(op==3) { printf("%d\n",rk(root[ver],x)); root[++cnt]=root[ver]; } if(op==4) printf("%d\n",find(ver,x,1)); if(op==5) printf("%d\n",pre(ver,x)); if(op==6) printf("%d\n",suc(ver,x)); } }
-
-