fhq-treap初学

codesonic

2018-07-13 21:50:50

Personal

原来你就是无旋treap??? fhq-treap的思想就是函数式编程,即通过简单函数的组合实现操作,这在fhq-treap中有很大体现 fhq-treap用两个函数merge和split实现了平衡树的主要操作 先来瞻仰一下这两个函数: merge: ```cpp void merge(int &x,int l,int r){ if(!l||!r) x=l+r; else if(rnd[l]<rnd[r]) x=l,merge(rs[x],rs[x],r),up(x); else x=r,merge(ls[x],l,ls[x]),up(x); } ``` merge把l和r两棵树合并成了x,代码很显然就不多说了~~(其实是因为我讲不通)~~ split: ```cpp void split(int x,int &l,int &r,int k){ if(!k) l=0,r=x; else if(k==size[x]) l=x,r=0; else if(k<=size[ls[x]]) r=x,split(ls[x],l,ls[x],k),up(x); else l=x,split(rs[x],rs[x],r,k-size[ls[x]]-1),up(x); } ``` split把x树分成了l和r两棵树 接下来是主要部分,也是fhq-treap用merge和split实现许多操作的思想体现 insert插入元素: ```cpp inline void insert(int delta){ int x,y,rk=rank(root,delta); split(root,x,y,rk); build(tmp,delta); merge(x,x,tmp); merge(root,x,y); } ``` insert函数里,先把整棵treap按要插入的值拆成了两棵,再把要加的节点和其中一半合并,最后两半一起合并重新变成完整的treap del删除元素 ```cpp inline void del(int delta){ int x,y,z,rk=rank(root,delta)+1; split(root,x,y,rk); split(x,x,z,rk-1); merge(root,x,y); } ``` 同理,把treap先拆成两半,然后把其中一半中的要删除的节点拆出来,再把那大的两半合起来,完毕 其他的操作也差不多啦 code for [P3369 【模板】普通平衡树](https://www.luogu.org/problemnew/show/P3369) ```cpp #include<cstdio> #include<algorithm> using namespace std; const int maxn=500010; int n,m,x,y,z,tot,opt; struct fhq_treap{ int rnd[maxn],sum[maxn],size[maxn],ls[maxn],rs[maxn],root,tmp; inline void build(int &x,int delta){ rnd[x=++tot]=rand()<<15|rand(); sum[x]=delta; size[x]=1; } inline void up(int x){ if(!x) return ; size[x]=size[ls[x]]+size[rs[x]]+1; } void merge(int &x,int l,int r){ if(!l||!r) x=l+r; else if(rnd[l]<rnd[r]) x=l,merge(rs[x],rs[x],r),up(x); else x=r,merge(ls[x],l,ls[x]),up(x); } void split(int x,int &l,int &r,int k){ if(!k) l=0,r=x; else if(k==size[x]) l=x,r=0; else if(k<=size[ls[x]]) r=x,split(ls[x],l,ls[x],k),up(x); else l=x,split(rs[x],rs[x],r,k-size[ls[x]]-1),up(x); } int rank(int x,int w){ if(!x) return 0; if(sum[x]>=w) return rank(ls[x],w); return rank(rs[x],w)+size[ls[x]]+1; } inline void insert(int delta){ int x,y,rk=rank(root,delta); split(root,x,y,rk); build(tmp,delta); merge(x,x,tmp); merge(root,x,y); } inline void del(int delta){ int x,y,z,rk=rank(root,delta)+1; split(root,x,y,rk); split(x,x,z,rk-1); merge(root,x,y); } inline int find(int delta) { int x,y,z,ans; split(root,x,y,delta); split(x,z,x,delta-1); ans=sum[x]; merge(x,z,x); merge(root,x,y); return ans; } inline int pre(int delta){ int x,y,z,ans,rk=rank(root,delta); split(root,x,y,rk); split(x,z,x,rk-1); ans=sum[x]; merge(x,z,x); merge(root,x,y); return ans; } inline int sub(int delta){ int x,y,z,ans,rk=rank(root,delta+1); split(root,x,y,rk+1); split(x,z,x,rk); ans=sum[x]; merge(x,z,x); merge(root,x,y); return ans; } }T; int main() { srand(2009); scanf("%d",&n); T.rnd[0]=T.sum[0]=(1<<30); while(n--){ int opt; scanf("%d%d",&opt,&x); if(opt==1) T.insert(x); else if(opt==2) T.del(x); else if(opt==3)printf("%d\n",T.rank(T.root,x)+1); else if(opt==4)printf("%d\n",T.find(x)); else if(opt==5)printf("%d\n",T.pre(x)); else printf("%d\n", T.sub(x)); } } ``` 文艺平衡树也是乱搞,对于要翻转的区间,交换左子树右子树,然后打标记即可 ```cpp // luogu-judger-enable-o2 // luogu-judger-enable-o2 // luogu-judger-enable-o2 #include<cstdio> #include<algorithm> using namespace std; const int maxn=500010; int n,m,x,y,z,tot,opt; inline void read(int &x){ x=0;int f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } struct fhq_treap{ int rnd[maxn],sum[maxn],size[maxn],ls[maxn],rs[maxn],root,tmp; bool rev[maxn]; inline void change(int x){ rev[x]^=1; swap(ls[x],rs[x]); } inline void down(int x) { if(!x) return; if(rev[x]) change(ls[x]),change(rs[x]); rev[x]=0; } inline void build(int &x,int delta){ rnd[x=++tot]=rand()<<15|rand(); sum[x]=delta; size[x]=1; } inline void up(int x){ if(!x) return ; size[x]=size[ls[x]]+size[rs[x]]+1; } void merge(int &x,int l,int r){ if(!l||!r) x=l+r; else if(rnd[l]<rnd[r]) down(x=l),merge(rs[x],rs[x],r),up(x); else down(x=r),merge(ls[x],l,ls[x]),up(x); } void split(int x,int &l,int &r,int k){ if(!k) l=0,r=x; else if(k==size[x]) l=x,r=0; else if(k<=size[ls[x]]) down(r=x),split(ls[x],l,ls[x],k),up(x); else down(l=x),split(rs[x],rs[x],r,k-size[ls[x]]-1),up(x); } inline void insert(int pos,int delta) { int x,y; split(root,x,y,pos); merge(x,x,delta); merge(root,x,y); } inline void del(int pos,int delta){ int x,y,z; split(root,x,y,pos); split(x,x,z,pos-1); merge(root,x,y); } inline void reverse(int l, int r) { int x,y,z; split(root,x,y,r); split(x,z,x,l-1); change(x); merge(x,z,x); merge(root,x,y); } void getans(int num){ int x,y,z; split(root,x,y,num); split(x,z,x,num-1); printf("%d ",sum[x]); merge(x,z,x); merge(root,x,y); } }T; int main() { srand(2009); read(n); read(m); T.rnd[0]=T.sum[0]=(1<<30); for(int i=1;i<=n;i++){ int tmp; T.build(tmp,i); T.merge(T.root,T.root,tmp); } while(m--){ read(x); read(y); T.reverse(x,y); } for(int i=1;i<=n;i++){ T.getans(i); } return 0; } ``` 又比splay短又比splay快的数据结构 似乎要全方位吊打splay了