文艺平衡树与可持久化文艺平衡树

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;
}

来个例题(超级毒瘤)

NOI2005 维修数列

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;
}
posted @ 2019-03-14 10:39  Jμdge  阅读(770)  评论(0编辑  收藏  举报