fhq_treap 总结
今天跟着zcg大神学了一发fhq_treap
发现在维护区间问题上fhq_treap不仅思维量小,而且代码量更小
是Splay的不错的替代品,不过至今还是有一些问题不能很好的解决
譬如查询某个数在序列中的第几个位置QAQ
fhq_treap的核心是split和merge可以logn的完成区间的分裂和合并
由于没有旋转所以可以支持可持久化
cojs 2314
可持久化fhq_treap的裸题,直接上代码
每次merge和split的时候新建一条链上的节点就可以啦
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; const int maxn=100010; int n,cur,d,op,x,y,z; char s[maxn]; struct Node{ char c;int fix,sz;Node *L,*R; Node(char x=0){fix=rand();sz=1;c=x;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){sz=lsize()+rsize()+1;} }*rt[maxn]; void read(int &num){ num=0;char ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void cpy(Node *&a,Node *b){ if(b==null)a=null; else a=new Node(),*a=*b; return; } void DFS(Node *rt){ if(rt==null)return; DFS(rt->L); putchar(rt->c);d+=(rt->c=='c'); DFS(rt->R); } void split(Node *rt,Node *&a,Node *&b,int k){ if(!k)cpy(b,rt),a=null; else if(rt->sz<=k)cpy(a,rt),b=null; else if(rt->lsize()>=k){ cpy(b,rt);split(rt->L,a,b->L,k); b->up(); }else{ cpy(a,rt);split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)cpy(rt,b); else if(b==null)cpy(rt,a); else if(a->fix<b->fix){ cpy(rt,a);merge(rt->R,a->R,b); rt->up(); }else{ cpy(rt,b);merge(rt->L,a,b->L); rt->up(); }return; } void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(s[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void UPD(Node *&rt,Node *pre,int x){ Node *a,*b,*c; split(pre,a,b,x);build(c,0,strlen(s)-1); merge(a,a,c);merge(rt,a,b); } void del(Node *&rt,Node *pre,int x,int y){ Node *a,*b,*c; split(pre,a,b,x-1);split(b,b,c,y); merge(rt,a,c); } void Get_ans(Node *rt,int x,int y){ Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,y); DFS(b);printf("\n"); } int main(){ freopen("persistable_editor.in","r",stdin); freopen("persistable_editor.out","w",stdout); read(n); for(int i=1;i<=n;++i){ read(op); if(op==1){ read(x);x-=d;scanf("%s",s);cur++; UPD(rt[cur],rt[cur-1],x); }else if(op==2){ read(x);read(y);x-=d;y-=d;cur++; del(rt[cur],rt[cur-1],x,y); }else{ read(x);read(y);read(z); x-=d;y-=d;z-=d; Get_ans(rt[x],y,z); } }return 0; }
cojs 347 地震
要求支持区间插入,区间删除,区间加和区间最大值查询
维护一个add标记并记录mx就可以啦
注意merge和split下传标记的时机,这里写的不是很正确,在维护数列的时候会看到这样写的问题
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; typedef long long LL; const int maxn=100010; int n,m,x,y,z,k; int a[maxn]; struct Node{ int mx,add,val,fix,sz;Node *L,*R; Node(int v=0){val=mx=v;add=0;fix=rand();sz=1;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){ sz=lsize()+rsize()+1; mx=val; if(L!=null)mx=max(mx,L->mx); if(R!=null)mx=max(mx,R->mx); } void down(){ if(L!=null){L->val+=add;L->mx+=add;L->add+=add;} if(R!=null){R->val+=add;R->mx+=add;R->add+=add;} add=0; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ rt->down(); b=rt;split(rt->L,a,b->L,k); b->up(); }else{ rt->down(); a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void UPD(int L,int R,int v){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->mx+=v;b->val+=v;b->add+=v; merge(a,a,b);merge(rt,a,c); } void modify(int x,int k){ Node *a,*b,*c; split(rt,a,b,x);build(c,1,k); merge(a,a,c);merge(rt,a,b); } void remove(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); merge(rt,a,c); } void Get_ans(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); printf("%d\n",b->mx); merge(a,a,b);merge(rt,a,c); } void debug(Node *rt){ if(rt==null)return; rt->down(); debug(rt->L); printf("%d ",rt->val); debug(rt->R); } int main(){ freopen("equake.in","r",stdin); freopen("equake.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build(rt,1,n); for(int i=1;i<=m;++i){ char ch=getchar(); while(ch<'!')ch=getchar(); if(ch=='R'){ scanf("%d%d%d",&x,&y,&z); UPD(x,y,z); }else if(ch=='I'){ scanf("%d%d",&x,&k); for(int j=1;j<=k;++j)scanf("%d",&a[j]); modify(x,k); }else if(ch=='M'){ scanf("%d%d",&x,&y); remove(x,y); }else{ scanf("%d%d",&x,&y); Get_ans(x,y); }//debug(rt);printf("\n"); }return 0; }
cojs 322 可可的文本编辑器
要求支持区间插入,区间删除,区间翻转操作
维护一个rev标记就可以了,每次push_down的时候交换L和R
注意这里的标记下的时机,因为split后面要查询lsize,所以要在之前下放
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; const int maxn=2100010; int n,pos=0; int len; char s[maxn]; char op[20]; struct Node{ char c;int sz,fix,rev;Node *L,*R; Node(char x=0){c=x;fix=rand();L=R=null;sz=1;rev=0;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){sz=lsize()+rsize()+1;} void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; }return; } }*rt; void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(s[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void insert(){ scanf("%d",&len); for(int i=1;i<=len;++i){ s[i]=getchar(); while(s[i]<32||s[i]>126)s[i]=getchar(); } Node *a,*b,*c; split(rt,a,b,pos);build(c,1,len); merge(a,a,c);merge(rt,a,b); } void del(){ scanf("%d",&len); Node *a,*b,*c; split(rt,a,b,pos);split(b,b,c,len); merge(rt,a,c); } void Get_rev(){ scanf("%d",&len); Node *a,*b,*c; split(rt,a,b,pos);split(b,b,c,len); b->rev^=1; merge(a,a,b);merge(rt,a,c); } void Get_print(){ Node *a,*b,*c; split(rt,a,b,pos);split(b,b,c,1); putchar(b->c);printf("\n"); merge(a,a,b);merge(rt,a,c); } int main(){ freopen("editor.in","r",stdin); freopen("editor.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",op+1); if(op[1]=='M')scanf("%d",&pos); else if(op[1]=='I')insert(); else if(op[1]=='D')del(); else if(op[1]=='R')Get_rev(); else if(op[1]=='G')Get_print(); else if(op[1]=='P')pos--; else pos++; }return 0; }
NOI 2005 维护数列
要求支持区间插入,区间删除,区间修改,区间翻转,区间求和和求最长连续子段和
求最长连续子段和是经典问题可以通过维护前缀最大值和后缀最大值以及最长连续子段和得到
区间翻转多一个rev标记,区间修改多一个vis标记
码码码就好了,QAQ,BZOJ卡空间,所以delete完了之后要回收一下
不得不说,fhq_treap比Splay好写多了
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<cstring> #define null NULL using namespace std; const int oo=2333; const int maxn=4000010; const int Max=0x2fffffff; int n,m,x,k,v; int a[maxn]; char op[20]; struct Node{ int rev,vis; int sum,l_max,r_max,mx; int val,fix,sz; Node *L,*R; Node(int v=0){rev=0;vis=oo;sum=l_max=r_max=mx=val=v;fix=rand();sz=1;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} int L_sum(){return L!=null?L->sum:0;} int R_sum(){return R!=null?R->sum:0;} int L_R_mx(){return L!=null?max(L->r_max,0):0;} int R_L_mx(){return R!=null?max(R->l_max,0):0;} int L_L_mx(){return L!=null?L->l_max:-Max;} int R_R_mx(){return R!=null?R->r_max:-Max;} int L_mx(){return L!=null?L->mx:-Max;} int R_mx(){return R!=null?R->mx:-Max;} void up(){ sz=lsize()+rsize()+1; sum=L_sum()+R_sum()+val; mx=max(L_mx(),R_mx()); mx=max(mx,L_R_mx()+val+R_L_mx()); l_max=max(L_L_mx(),L_sum()+val+R_L_mx()); r_max=max(R_R_mx(),R_sum()+val+L_R_mx()); } void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1,swap(L->l_max,L->r_max); if(R!=null)R->rev^=1,swap(R->l_max,R->r_max); rev=0; } if(vis!=oo){ if(L!=null){ L->val=L->vis=vis; L->sum=(L->sz)*vis; L->l_max=L->r_max=L->mx=max(vis,L->sum); } if(R!=null){ R->val=R->vis=vis; R->sum=(R->sz)*vis; R->l_max=R->r_max=R->mx=max(vis,R->sum); }vis=oo; }return; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ split(rt->L,a,rt->L,k); rt->up();b=rt; }else{ split(rt->R,rt->R,b,k-(rt->lsize())-1); rt->up();a=rt; }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); merge(a->R,a->R,b); a->up();rt=a; }else{ b->down(); merge(b->L,a,b->L); b->up();rt=b; }return; } void insert(){ scanf("%d%d",&x,&k); for(int i=1;i<=k;++i)scanf("%d",&a[i]); Node *a,*b,*c; split(rt,a,b,x);build(c,1,k); merge(a,a,c);merge(rt,a,b); } void DFS_del(Node *x){ if(x==null)return; DFS_del(x->L); DFS_del(x->R); delete x; return; } void del(){ scanf("%d%d",&x,&k); Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,k); merge(rt,a,c);DFS_del(b); } void Get_modify(){ scanf("%d%d%d",&x,&k,&v); Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,k); b->val=b->vis=v; b->sum=(b->sz)*v; b->l_max=b->r_max=b->mx=max(v,b->sum); merge(a,a,b);merge(rt,a,c); } void Get_rev(){ scanf("%d%d",&x,&k); Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,k); b->rev^=1;swap(b->l_max,b->r_max); merge(a,a,b);merge(rt,a,c); } void Get_sum(){ scanf("%d%d",&x,&k); Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,k); if(b==null)printf("0\n"); else printf("%d\n",b->sum); merge(a,a,b);merge(rt,a,c); } void Get_max(){printf("%d\n",rt->mx);} int main(){ freopen("seq2005.in","r",stdin); freopen("seq2005.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build(rt,1,n); for(int i=1;i<=m;++i){ scanf("%s",op+1); int len=strlen(op+1); if(op[1]=='I')insert(); else if(op[1]=='D')del(); else if(op[1]=='R')Get_rev(); else if(op[1]=='G')Get_sum(); else if(op[1]=='M'){ if(op[3]=='K')Get_modify(); else Get_max(); } }return 0; }
BZOJ 序列终结者
QAQ 操作上面都有了 QAQ
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; const int maxn=100010; int n,m; int type,L,R,v; struct Node{ int mx,add,val,fix,sz,rev; Node *L,*R; Node(int v=0){mx=val=v;add=0;fix=rand();sz=1;rev=0;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){ sz=lsize()+rsize()+1; mx=val; if(L!=null)mx=max(mx,L->mx); if(R!=null)mx=max(mx,R->mx); } void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; } if(add!=0){ if(L!=null){L->mx+=add;L->val+=add;L->add+=add;} if(R!=null){R->mx+=add;R->val+=add;R->add+=add;} add=0; }return; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void UPD(int L,int R,int v){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->mx+=v;b->add+=v;b->val+=v; merge(a,a,b);merge(rt,a,c); } void Get_rev(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->rev^=1; merge(a,a,b);merge(rt,a,c); } void Get_max(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); printf("%d\n",b->mx); merge(a,a,b);merge(rt,a,c); } void debug(Node *rt){ if(rt==null)return; rt->down(); debug(rt->L); printf("%d ",rt->val); debug(rt->R); } int main(){ scanf("%d%d",&n,&m); build(rt,1,n); for(int i=1;i<=m;++i){ scanf("%d",&type); if(type==1){ scanf("%d%d%d",&L,&R,&v); UPD(L,R,v); }else if(type==2){ scanf("%d%d",&L,&R); Get_rev(L,R); }else{ scanf("%d%d",&L,&R); Get_max(L,R); } }return 0; }
BZOJ 文艺平衡树
随便写的水题
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; const int maxn=100010; int n,m,L,R; int a[maxn]; struct Node{ int rev,fix,val,sz; Node *L,*R; Node(int v=0){rev=0;fix=rand();val=v;sz=1;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){sz=lsize()+rsize()+1;} void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; }return; } }*rt; void print(Node *rt){ if(rt==null)return; rt->down(); print(rt->L); printf("%d ",rt->val); print(rt->R); } void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void Get_rev(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->rev^=1; merge(a,a,b);merge(rt,a,c); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)a[i]=i; build(rt,1,n); for(int i=1;i<=m;++i){ scanf("%d%d",&L,&R); Get_rev(L,R); }print(rt); return 0; }
hdu 3487
跟文艺平衡树差不多,貌似复杂一点,不过fhq_treap直接秒
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; const int maxn=300010; int n,m,x,y,z,L,R; int a[maxn]; int ans[maxn],tot; char op[20]; struct Node{ int sz,fix,val,rev; Node *L,*R; Node(int v=0){val=v;fix=rand();sz=1;L=R=null;rev=0;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){sz=lsize()+rsize()+1;} void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; }return; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void Get_rev(){ scanf("%d%d",&L,&R); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->rev^=1; merge(a,a,b);merge(rt,a,c); } void cut(){ scanf("%d%d%d",&x,&y,&z); int len=y-x+1; Node *a,*b,*c; split(rt,a,b,x-1);split(b,b,c,len); merge(a,a,c);split(a,a,c,z); merge(a,a,b);merge(rt,a,c); } void print(Node *rt){ if(rt==null)return; rt->down(); print(rt->L); ans[++tot]=(rt->val); print(rt->R); } void DFS_del(Node *rt){ if(rt==null)return; DFS_del(rt->L); DFS_del(rt->R); delete rt; return; } int main(){ while(scanf("%d%d",&n,&m)==2){ if(n==-1&&m==-1)break; for(int i=1;i<=n;++i)a[i]=i; build(rt,1,n); for(int i=1;i<=m;++i){ scanf("%s",op+1); if(op[1]=='C')cut(); else Get_rev(); }tot=0;print(rt); for(int i=1;i<=tot;++i){ printf("%d",ans[i]); if(i==tot)printf("\n"); else printf(" "); } DFS_del(rt); }return 0; }
UVa 11922
跟上面的题目大同小异QAQ
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define null NULL using namespace std; const int maxn=100010; int n,m,L,R; int a[maxn]; struct Node{ int sz,fix,rev,val; Node *L,*R; Node(int v=0){val=v;rev=0;fix=rand();sz=1;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){sz=lsize()+rsize()+1;} void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; }return; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void Get_rev(){ scanf("%d%d",&L,&R); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->rev^=1; merge(a,a,c);merge(rt,a,b); } void print(Node *rt){ if(rt==null)return; rt->down(); print(rt->L); printf("%d\n",rt->val); print(rt->R); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)a[i]=i; build(rt,1,n); for(int i=1;i<=m;++i)Get_rev(); print(rt); return 0; }
POJ 3580
一道操作有些繁琐的数据结构题目,fhq_treap直接上码码码就好了
循环移动说白了就是把序列劈成两半然后交换左右,注意T可能是负数
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define null NULL using namespace std; const int maxn=100010; int n,L,R,v,m; int a[maxn]; char op[22]; struct Node{ int sz,fix,add,val,mn,rev; Node *L,*R; Node(int v=0){val=mn=v;add=0;fix=rand();sz=1;rev=0;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){ sz=lsize()+rsize()+1;mn=val; if(L!=null)mn=min(mn,L->mn); if(R!=null)mn=min(mn,R->mn); } void down(){ if(rev){ swap(L,R); if(L!=null)L->rev^=1; if(R!=null)R->rev^=1; rev=0; } if(add!=0){ if(L!=null)L->val+=add,L->add+=add,L->mn+=add; if(R!=null)R->val+=add,R->add+=add,R->mn+=add; add=0; }return; } }*rt; void debug(Node *rt){ if(rt==null)return; rt->down(); debug(rt->L); printf("%d ",rt->val); debug(rt->R); } void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void Get_add(){ scanf("%d%d%d",&L,&R,&v); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->add+=v;b->mn+=v;b->val+=v; merge(a,a,b);merge(rt,a,c); } void insert(){ scanf("%d%d",&L,&v); Node *a,*b,*c;b=new Node(v); split(rt,a,c,L); merge(a,a,b);merge(rt,a,c); } void del(){ scanf("%d",&L); Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,1); merge(rt,a,c);delete b; } void Get_min(){ scanf("%d%d",&L,&R); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); printf("%d\n",b->mn); merge(a,a,b);merge(rt,a,c); } void Get_rev(){ scanf("%d%d",&L,&R); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->rev^=1; merge(a,a,b);merge(rt,a,c); } void Get_move(){ scanf("%d%d%d",&L,&R,&v); int len=R-L+1;v%=len; if(v<0)v+=len; Node *a,*b,*c,*d; split(rt,a,b,L-1);split(b,b,c,len); split(b,b,d,len-v); merge(a,a,d);merge(a,a,b);merge(rt,a,c); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build(rt,1,n);scanf("%d",&m); for(int i=1;i<=m;++i){ scanf("%s",op+1); if(op[1]=='A')Get_add(); else if(op[1]=='I')insert(); else if(op[1]=='D')del(); else if(op[1]=='M')Get_min(); else if(op[1]=='R'){ if(op[4]=='E')Get_rev(); else Get_move(); }//debug(rt);printf("\n"); }return 0; }
POJ 3468
不知道为什么一道线段树的题目混进来了,不管怎么样强行用fhq_treap做一发
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; typedef long long LL; const int maxn=100010; int n,m; int L,R,v; int a[maxn]; struct Node{ LL sum,val,add;Node *L,*R; int fix,sz; Node(LL v=0){val=sum=v;fix=rand();sz=1;add=0;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} void up(){ sz=lsize()+rsize()+1; sum=val; if(L!=null)sum+=L->sum; if(R!=null)sum+=R->sum; } void down(){ if(add!=0){ if(L!=null)L->val+=add,L->add+=add,L->sum+=(L->sz)*add; if(R!=null)R->val+=add,R->add+=add,R->sum+=(R->sz)*add; add=0; }return; } }*rt; void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(a[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(rt!=null)rt->down(); if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ a->down(); rt=a;merge(rt->R,a->R,b); rt->up(); }else{ b->down(); rt=b;merge(rt->L,a,b->L); rt->up(); }return; } void Get_add(){ scanf("%d%d%d",&L,&R,&v); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); b->add+=v;b->sum+=(b->sz)*v;b->val+=v; merge(a,a,b);merge(rt,a,c); } void Get_sum(){ scanf("%d%d",&L,&R); int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); if(b==null)printf("0\n"); else printf("%lld\n",b->sum); merge(a,a,b);merge(rt,a,c); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build(rt,1,n); for(int i=1;i<=m;++i){ char ch=getchar(); while(ch<'!')ch=getchar(); if(ch=='C')Get_add(); else Get_sum(); }return 0; }
BZOJ 1014
原来写的Splay维护hash值,把Splay换成fhq_treap就可以了
比Splay好写多了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #define null NULL using namespace std; typedef long long LL; const int maxn=100010; const int base=13331; int n,m,L,R; char s[maxn]; LL xp[maxn]; struct Node{ int fix,sz;char c; LL h;Node *L,*R; Node(char x=0){c=x-'a';sz=1;fix=rand();h=c;L=R=null;} int lsize(){return L!=null?L->sz:0;} int rsize(){return R!=null?R->sz:0;} LL L_h(){return L!=null?L->h:0;} LL R_h(){return R!=null?R->h:0;} void up(){ sz=lsize()+rsize()+1; h=L_h()+c*xp[lsize()]+R_h()*xp[lsize()+1]; } }*rt; void debug(Node *rt){ if(rt==null)return; debug(rt->L); putchar(rt->c+'a'); debug(rt->R); } void build(Node *&rt,int L,int R){ if(L>R)return; int mid=(L+R)>>1; rt=new Node(s[mid]); build(rt->L,L,mid-1); build(rt->R,mid+1,R); rt->up(); } void split(Node *rt,Node *&a,Node *&b,int k){ if(!k)b=rt,a=null; else if(rt->sz<=k)a=rt,b=null; else if(rt->lsize()>=k){ b=rt;split(rt->L,a,b->L,k); b->up(); }else{ a=rt;split(rt->R,a->R,b,k-(rt->lsize())-1); a->up(); }return; } void merge(Node *&rt,Node *a,Node *b){ if(a==null)rt=b; else if(b==null)rt=a; else if(a->fix<b->fix){ rt=a;merge(rt->R,a->R,b); rt->up(); }else{ rt=b;merge(rt->L,a,b->L); rt->up(); }return; } LL Get_hash(int L,int R){ int len=R-L+1; Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,len); LL ans=b->h; merge(a,a,b);merge(rt,a,c); return ans; } void Get_LCP(){ scanf("%d%d",&L,&R); int l=0,r=min(n-L+1,n-R+1); while(l<r){ int mid=l+((r-l+1)>>1); if(Get_hash(L,L+mid-1)==Get_hash(R,R+mid-1))l=mid; else r=mid-1; }printf("%d\n",l);return; } void Get_modify(){ scanf("%d",&L); char ch=getchar(); while(ch<'!')ch=getchar(); Node *a,*b,*c; split(rt,a,b,L-1);split(b,b,c,1); b->c=b->h=ch-'a'; merge(a,a,b);merge(rt,a,c); } void insert(){ scanf("%d",&L); char ch=getchar(); while(ch<'!')ch=getchar(); Node *a,*b,*c; split(rt,a,c,L);b=new Node(ch); merge(a,a,b);merge(rt,a,c); } int main(){ scanf("%s",s+1);n=strlen(s+1); xp[0]=1; for(int i=1;i<=100000;++i)xp[i]=xp[i-1]*base; build(rt,1,n);scanf("%d",&m); for(int i=1;i<=m;++i){ char ch=getchar(); while(ch<'!')ch=getchar(); if(ch=='Q')Get_LCP(); else if(ch=='R')Get_modify(); else if(ch=='I')insert(),n++; }return 0; }
总结:
1、fhq_treap的核心是split和merge,所以在写这两个函数的时候一定要一次写对
注意边界的判断和是a还是b的判断,如果是a,向右孩子方向移动,如果是b,向左孩子方向移动就可以啦
2、对于区间操作,每次两个split直接取出区间然后改一下就可以了
下传标记要在查询相关信息和递归之前,每次递归后要up
必要时要回收del的空间
3、对于标记的下放一定要讨论清楚,并且考虑标记之间的相互作用以及标记对维护值的作用
自己的数据结构能力越来越强了呢,加油!
八月份!三个月!