今天跟着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、对于标记的下放一定要讨论清楚,并且考虑标记之间的相互作用以及标记对维护值的作用

自己的数据结构能力越来越强了呢,加油!

八月份!三个月!

fhq_treap 总结的更多相关文章

  1. [总结] fhq_Treap 学习笔记

    无旋版 $Treap$. 只需要两个操作即可达到 $splay$ 的所有功能 1.$split$ 它的主要思想就是把一个 $Treap$ 分成两个. $split$ 操作有两种类型,一种是按照权值分配 ...

  2. BZOJ1500 [NOI2005]维修数列-fhq_Treap

    题面见这里 反正是道平衡树,就拿 fhq_Treap 写了写... 这道题思路基本是围绕“用 Treap 维护中序遍历” 和 中序遍历的性质 来进行的操作 所以就可以类比线段树进行一些操作 1. 建树 ...

  3. 用 fhq_Treap 实现可持久化平衡树

    支持对历史版本进行操作的平衡树 Treap 和 Splay 都是旋来旋去的 这样平衡树可持久化听起来不太好搞? 还有 fhq_Treap ! 每次涉及操作就复制一个节点出来 操作历史版本就继承它的根继 ...

  4. Treap与fhq_Treap学习笔记

    1.普通Treap 通过左右旋来维护堆的性质 左右旋是不改变中序遍历的 #include<algorithm> #include<iostream> #include<c ...

  5. fhq_treap 学习笔记

    前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap. 简介:fhq_treap功能强大,支持splay支持的所有操作,代 ...

  6. 「模板」 FHQ_Treap 区间翻转

    「模板」 FHQ_Treap 区间翻转 没有旋转的 Treap 实现区间操作的功能,很好理解,也很好写,只是速度不算太快. 对于要翻转的区间,把整棵 Treap(存有区间 \([1,n]\) 的信息) ...

  7. 「模板」 FHQ_Treap

    「模板」 FHQ_Treap 我也是偶然发现我还没发过FHQ_Treap的板子. 那就发一波吧. 这个速度实在不算快,但是不用旋转,并且好写. 更重要的是,Splay 可以做的事情它都可以做!比如区间 ...

  8. POJ 3580 SuperMemo (FHQ_Treap)

    题意:让你维护一个序列,支持以下6种操作: ADD x y d: 第x个数到第y个数加d . REVERSE x y : 将区间[x,y]中的数翻转 . REVOLVE x y t :将区间[x,y] ...

  9. [note]fhq_treap

    fhq_treap 这东西据说是某个叫范浩强的神仙搞出来的, 他的这种treap可以不用旋转并且资磁很多平衡树操作, 复杂度通过随机的键值来保证(树大致平衡,期望一次操作复杂度\(logn\)) 依靠 ...

随机推荐

  1. Ping N个IP测试网络连通性

    #-----------------------Smokeping移动节点-------------------##! /bin/bashecho "------------- Statin ...

  2. Java基础(二)

    下面来实现一个小程序,要求如下: 从键盘接收一个字符串,程序对其中所有的字符进行排序,例如键盘输入:helloitcast程序打印acehillostt 步骤分析: 1.键盘录入字符串,Scanner ...

  3. Python 的列表解析和生成表达式的异同

      Python中的列表解析和生成表达式是非常好的特性,他们的形式相似,但是应用场景不太一样. 相似点 列表解析和生成表达式最大的相似点是使用形式: [expr for iter_var in ite ...

  4. C#不同页面之间通信的方法

    以前做项目的时候经常头疼两个页面之间的交互(汗),这几天看的MVVM项目,忽然感觉好简单的!我自己写了个简单的demo 可以简单实现2个页面之间的交互,新人第一次发博客,不喜勿喷 代码很简单,注释我就 ...

  5. static与全局与局部变量的区别

    转自:http://www.cnblogs.com/lzjsky/archive/2010/11/19/1882064.html 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变 ...

  6. python之域与属性

    python, javascript中域与属性是二个不同的概念, 域就是变量, 而属性则是符合某些约束, 例如getter, setter...等的特殊"变量". python中使 ...

  7. PHP dirname() 函数 __FILE__ __DIR__

    __DIR__返回文件所处的目录,除非是根目录,否则末尾不带\ __FILE__ 返回文件路径 dirname(__DIR__) 文件所处目录的上级目录,末尾也不带斜杠

  8. NSRange、NSPoint(CGPoint)、NSSize(CGSize)、NSRect(CGRect)

    1.NSRange: typedef struct _NSRange { NSUInteger location; NSUInteger length; } NSRange; NSRange本身是系统 ...

  9. OC中的点语法,成员变量的作用域

    点语法 点语法本质是函数的调用,不是像java中那样,是用来访问成员变量的:oc中访问成员变量是用 -> 访问的: Person *p = [Person new]; p.age = 10; / ...

  10. MITK Tutorial(二)

    目标: 生成MITK 插件包括一个新用户交互的视图,并调用一些ITK filters. Step 1: How to create a new MITK Plugin 可以选择用Plugin Gene ...