文艺平衡树与可持久化文艺平衡树
FHQ 大法好啊!
什么?你说 FHQ 不能维护 LCT ? splay 也不能可持久化啊!
关于文艺平衡树:
就是用 FHQtreap 维护区间,reverse 的话就打个标记,裂点的时候释放,FHQ treap 不会的点这里
其实这里什么懒标记也就是类似线段树的操作吧,要查儿子水表了就把标记给儿子...
板子在下面 (毒瘤压行人 zjq ),看不惯就 Ctrl shift A 嘛
//by Judge
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int inf=1e9+7;
const int M=1e5+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){ int x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(int x,char chr=' '){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,m;
namespace FHQTreap{ arr pos,siz,w,fl; int rt,tot,son[M][2];
inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); }
inline void pushup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
inline int newnode(int x){w[++tot]=x,siz[tot]=1,pos[tot]=Rand();return tot;}
inline void pushdown(int x){swap(son[x][0],son[x][1]),fl[son[x][0]]^=1,fl[son[x][1]]^=1,fl[x]=0;}
int merge(int x,int y){ if(!x||!y) return x|y;
if(pos[x]<pos[y]){if(fl[x]) pushdown(x); son[x][1]=merge(son[x][1],y),pushup(x); return x;}
if(fl[y]) pushdown(y); son[y][0]=merge(x,son[y][0]),pushup(y); return y;
}
void split(int rt,int k,int& x,int& y){
if(!rt) return x=y=0,void(); if(fl[rt]) pushdown(rt);
if(siz[son[rt][0]]<k) x=rt,split(son[rt][1],k-siz[son[rt][0]]-1,son[rt][1],y);
else y=rt,split(son[rt][0],k,x,son[rt][0]); pushup(rt);
}
void output(int x){ if(!x) return ; if(fl[x]) pushdown(x);
output(son[x][0]),print(w[x]),output(son[x][1]);
}
} using namespace FHQTreap;
int main(){ n=read(),m=read();
for(int i=1;i<=n;++i)
rt=merge(rt,newnode(i));
for(int i=1,l,r,a,b,c;i<=m;++i){
l=read(),r=read(),split(rt,l-1,a,b);
split(b,r-l+1,b,c),fl[b]^=1;
rt=merge(a,merge(b,c));
} return output(rt),Ot(),0;
}
来个例题(超级毒瘤)
mmp 这题真的毒瘤啊!就是一堆操作恶心你,完了读入操作还是字符串,烦
然后这里的建树就是比较骚的了,由于每次都是直接加一大块序列,如果一个一个点塞的话可能就挂掉了,那么我们可以用栈来维护建树过程
然后还是懒标记,不同的是这里有区间赋值的懒标记...
//by Judge
#include<cstdio>
#include<iostream>
using namespace std;
const int inf=1e9+7,M=5e5+3;
inline int Max(int a,int b){return a>b?a:b;}
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){ int x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-'){
c=getchar(); if(isdigit(c)) f=-1; break;
} for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} inline int cread(){ char c=getchar(),s[9];
int x=0; for(;!isupper(c);c=getchar());
for(;isupper(c)||c=='-';c=getchar()) s[++x]=c;
if(s[1]=='I') return 1; if(s[1]=='D') return 2;
if(s[1]=='R') return 4; if(s[1]=='G') return 5;
if(s[3]=='K') return 3; if(s[3]=='X') return 6;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(int x,char chr='\n'){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,m,op,x,l,r,a,b,c,A[M];
namespace FHQTreap{
int rt,tot,tail,pool[M],top,stk[M];
inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); }
struct node{ int val,pos,siz,sum,ls,rs,lmx,rmx,mx,re,co; node(){ls=rs=re=0,co=inf;}
inline void init(int x){ lmx=rmx=Max(0,x),mx=sum=val=x,siz=1,pos=Rand();}
inline void cover(int x){co=val=x,sum=x*siz,rmx=lmx=Max(0,sum),mx=Max(sum,x);}
inline void rever(){swap(ls,rs),swap(lmx,rmx),re^=1;}
}t[M];
inline int newnode(int x){ int z=tail?pool[tail--]:++tot;return t[z]=node(),t[z].init(x),z;}
inline void pushup(int x){ if(!x) return ; t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;
t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum+t[x].val,t[x].mx=t[t[x].ls].rmx+t[x].val+t[t[x].rs].lmx;
if(t[x].ls) t[x].mx=Max(t[x].mx,t[t[x].ls].mx); if(t[x].rs) t[x].mx=Max(t[x].mx,t[t[x].rs].mx);
t[x].lmx=Max(Max(t[t[x].ls].sum+t[x].val+t[t[x].rs].lmx,t[t[x].ls].lmx),0);
t[x].rmx=Max(Max(t[t[x].rs].sum+t[x].val+t[t[x].ls].rmx,t[t[x].rs].rmx),0);
}
inline void pushdown(int x){ if(!x) return ;
if(t[x].re) t[t[x].ls].rever(),t[t[x].rs].rever(),t[x].re=0;
if(t[x].co!=inf) t[t[x].ls].cover(t[x].co),t[t[x].rs].cover(t[x].co),t[x].co=inf;
}
int merge(int x,int y){ if(!x||!y) return x|y; pushdown(x),pushdown(y);
if(t[x].pos<t[y].pos) return t[x].rs=merge(t[x].rs,y),pushup(x),x;
else return t[y].ls=merge(x,t[y].ls),pushup(y),y;
}
void split(int rt,int k,int& x,int& y){ if(!rt) return x=y=0,void(); pushdown(rt);
if(t[t[rt].ls].siz>=k) y=rt,split(t[y].ls,k,x,t[y].ls),pushup(y);
else x=rt,split(t[x].rs,k-t[t[x].ls].siz-1,t[x].rs,y),pushup(x);
}
inline int build(int* A,int n){ int a,b,c;
top=0,stk[++top]=b=newnode(A[1]);
for(int i=2;i<=n;++i){ c=newnode(A[i]),a=0;
while(top&&t[stk[top]].pos>t[c].pos)
a=stk[top--],pushup(a);
if(top) t[stk[top]].rs=c;
t[c].ls=a,stk[++top]=c; if(top==1) b=c;
} while(top) pushup(stk[top--]); return b;
}
inline void insert(){
l=read(),r=read(),split(rt,l,a,c);
for(int i=1;i<=r;++i) A[i]=read();
b=build(A,r),rt=merge(a,merge(b,c));
}
inline void delet(int x){
if(!x) return ; pool[++tail]=x;
delet(t[x].ls),delet(t[x].rs);
}
inline void delet(){ l=read(),r=read();
split(rt,l-1,a,b),split(b,r,b,c);
delet(b),rt=merge(a,c);
}
inline void cover(){ l=read(),r=read(),x=read();
split(rt,l-1,a,b),split(b,r,b,c);
t[b].cover(x),rt=merge(a,merge(b,c));
}
inline void rever(){ l=read(),r=read();
split(rt,l-1,a,b),split(b,r,b,c);
t[b].rever(),rt=merge(a,merge(b,c));
}
inline void q_sum(){ l=read(),r=read();
split(rt,l-1,a,b),split(b,r,b,c);
print(t[b].sum),rt=merge(a,merge(b,c));
}
} using namespace FHQTreap;
int main(){ n=read(),m=read();
for(int i=1;i<=n;++i) A[i]=read();
for(rt=build(A,n);m;--m){ op=cread();
if(op==1) insert();
else if(op==2) delet();
else if(op==3) cover();
else if(op==4) rever();
else if(op==5) q_sum();
else if(op==6) print(t[rt].mx);
} return Ot(),0;
}
关于可持久化文艺平衡树
Luogu板子题,这玩意儿应该只能 \(FHQ treap\) 做
(就是好奇为什么空间要开那么大,我算出来的话是 log 级别的啊...好吧其实也差不多,算上常数的嘛)
总体来讲不是非常的 nan ,其实就是江 可持久化线段树 和 FHQ treap 两道紫题并在了一起变成了黑题,假的【雾
但可持久化确实大多是用了可持久化线段树的思路,考虑新建节点,保留历史版本什么的...
于是就这么愉快的 A 了此题...
聊太多了 QWQ ,开始谈题目
首先你得 A 了文艺平衡树(用 FHQ treap A 的) ,FHQ treap 不会的点这里
其次你得学会可持久化的思想,可持久化不会的点这里 (其实是主席树?但是想法类似?)
其实别的都是板子,就是 split 的时候比较特殊罢了,还有下穿标记的时候也是,需要新建节点然后连到父节点那里
//by Judge
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int N=2e5;
const int M=(N<<7)+3; //注意看
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline ll read(){ ll x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(ll x,char chr='\n'){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,op,v,l,r,a,b,c; ll ans;
namespace FHQTreap{ arr rt,pos,siz,fl;
ll w[M],sum[M]; int now,tot,son[M][2];
inline int Rand() { static int seed=703;return seed=int(seed*48271LL%(~0u>>1));}
inline int newnode(ll x=0){return w[++tot]=x,sum[tot]=x,pos[tot]=Rand(),siz[tot]=1,tot;}
inline int copy(int x){ int y=newnode(); //复制节点最好单独来一个小函数...然后里面要 copy 的别忘 copy 全,我被这玩意儿坑了两次
son[y][0]=son[x][0],son[y][1]=son[x][1],siz[y]=siz[x];
w[y]=w[x],sum[y]=sum[x],fl[y]=fl[x]; return y;
}
inline void pushup(int x){
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x];
}
inline void pushdown(int x){ if(!fl[x]) return; //注意看+1
if(son[x][0]) son[x][0]=copy(son[x][0]);
if(son[x][1]) son[x][1]=copy(son[x][1]);
fl[son[x][0]]^=1,fl[son[x][1]]^=1;
swap(son[x][0],son[x][1]),fl[x]=0;
}
int merge(int x,int y){ if(!x||!y) return x|y; //merge 好像没什么特别的
if(pos[x]<pos[y]) return pushdown(x),son[x][1]=merge(son[x][1],y),pushup(x),x;
else return pushdown(y),son[y][0]=merge(x,son[y][0]),pushup(y),y;
}
void split(int rt,int k,int& x,int& y){ //注意看+1
if(!rt) return x=y=0,void(); pushdown(rt);
if(siz[son[rt][0]]>=k) y=copy(rt),split(son[y][0],k,x,son[y][0]),pushup(y); //这里是copy了之前的节点然后直接拿他做下去了
else x=copy(rt),split(son[x][1],k-siz[son[x][0]]-1,son[x][1],y),pushup(x); //同上
}
} using namespace FHQTreap;
int main(){ //主函数照着题目打就好了
for(n=read();n;--n){ v=read(),op=read();
if(op==1){
l=read()^ans,r=read()^ans,split(rt[v],l,a,b);
rt[++now]=merge(a,merge(newnode(r),b));
} else if(op==2){
l=read()^ans,split(rt[v],l-1,a,b);
split(b,1,b,c),rt[++now]=merge(a,c);
} else if(op==3){ l=read()^ans,r=read()^ans;
split(rt[v],r,a,c),split(a,l-1,a,b);
fl[b]^=1,rt[++now]=merge(a,merge(b,c));
} else if(op==4){ l=read()^ans,r=read()^ans;
split(rt[v],r,a,c),split(a,l-1,a,b);
print(ans=sum[b]),rt[++now]=merge(a,merge(b,c));
}
} return Ot(),0;
}