平衡树区间操作板子

前几天知道平衡树也能像线段树一样实现操作。
并且还能轻易实现一些线段树很难做到的东西。
如区间翻转。

以下题目本人均用\(fhq-treap\)完成

先完成文艺平衡树序列终结者[CQOI2014]排序机械臂
接下来的一道经典例题大概就是上面的三道的总和
[NOI2005] 维护数列

题目大意

实现一个数据结构,支持一下操作:

  • 在任意位置插入一堆数
  • 在任意位置删除一堆数
  • 在任意位置修改一堆数
  • 翻转任意区间
  • 查询任意区间和
  • 查询整个序列的最大子段和

    做完先前三题你就能知道大致思路了,下面讲述一些注意事项。
  1. 对于插入,很显然不能一个一个插,你可以先把要插入的\(tot\)个数形成一棵平衡树,然后与原序列的平衡树合并。
    但这样会\(T\)\(20pts\),其实你就可以像线段树那样“分治建树”,可以很巧妙的将插入复杂度由\(O(totlog_2tot)\)降为\((log^2tot)\)
  2. 此题卡空间,在删除时应该“回收利用”节点编号。
  3. 一些零碎的细节:最大子段和不能为空,记得\(pushdown\)\(update\),不要操作空节点等。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,T,cnt,rt;
int ls[N],rs[N],val[N],siz[N],pfer[N];
int sum[N],lmx[N],rmx[N],a[N];
int rev[N],tag[N],dat[N];
int sk[N],top;
bool ct[N];
int read(){
	int A=0,F=1;
	char C=getchar();
	while(C<'0'||C>'9'){if(C=='-')F=-1;C=getchar();}
	while(C>='0'&&C<='9'){A=(A<<1)+(A<<3)+C-'0';C=getchar();}
	return A*F;
}
int New(int k){
	int p=top?sk[top--]:++cnt;
	ls[p]=rs[p]=rev[p]=tag[p]=ct[p]=0;
	sum[p]=k;val[p]=k;
	lmx[p]=max(k,0);
	rmx[p]=max(k,0);
	dat[p]=k;
	siz[p]=1;pfer[p]=rand()*rand();
	return p;
}
void update(int p){
	if(!p)return;
	siz[p]=siz[ls[p]]+siz[rs[p]]+1;
	sum[p]=sum[ls[p]]+sum[rs[p]]+val[p];
	lmx[p]=max(max(lmx[ls[p]],sum[ls[p]]+val[p]+lmx[rs[p]]),0);
	rmx[p]=max(max(rmx[rs[p]],sum[rs[p]]+val[p]+rmx[ls[p]]),0);
	dat[p]=max(val[p],val[p]+rmx[ls[p]]+lmx[rs[p]]);
	if(ls[p])dat[p]=max(dat[p],dat[ls[p]]);
	if(rs[p])dat[p]=max(dat[p],dat[rs[p]]);
}
void Re(int p){
	if(!p)return;
	swap(ls[p],rs[p]);
	swap(lmx[p],rmx[p]);
	rev[p]^=1;
}
void Co(int p,int v){
	val[p]=tag[p]=v;
	sum[p]=siz[p]*v;
	lmx[p]=rmx[p]=max(0,sum[p]);
	dat[p]=max(v,sum[p]);
	ct[p]=1;
}
void pushdown(int p){
	if(!p)return;
	if(rev[p]){
		if(ls[p])Re(ls[p]);
		if(rs[p])Re(rs[p]);
		rev[p]=0;
	}
	if(ct[p]){
		if(ls[p])Co(ls[p],tag[p]);
		if(rs[p])Co(rs[p],tag[p]);
		tag[p]=ct[p]=0;
	}
}
void split(int p,int sz,int &x,int &y){
	if(!p){x=y=0;return;}
	pushdown(p);
	if(siz[ls[p]]+1<=sz){x=p;split(rs[p],sz-siz[ls[p]]-1,rs[p],y);}
	else{y=p;split(ls[p],sz,x,ls[p]);}
	update(p);
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(pfer[x]>pfer[y]){
		pushdown(x);
		rs[x]=merge(rs[x],y);
		update(x);
		return x;
	}
	else{
		pushdown(y);
		ls[y]=merge(x,ls[y]);
		update(y);
		return y;
	}
}
void recycle(int p){
	if(!p)return;
	sk[++top]=p;
	recycle(ls[p]);
	recycle(rs[p]);
}
void del(int l,int r){
	int x,y,z;
	split(rt,l-1,x,y);
	split(y,r-l+1,y,z);
	recycle(y);
	rt=merge(x,z);
}
void modify(int l,int r,int k){
	int x,y,z;
	split(rt,l-1,x,y);
	split(y,r-l+1,y,z);
	Co(y,k);
	rt=merge(merge(x,y),z);
}
void reverse(int l,int r){
	int x,y,z;
	split(rt,l-1,x,y);
	split(y,r-l+1,y,z);
	Re(y);
	rt=merge(merge(x,y),z);
}
int qsum(int l,int r){
	int x,y,z,ans;
	split(rt,l-1,x,y);
	split(y,r-l+1,y,z);
	ans=sum[y];
	rt=merge(merge(x,y),z);
	return ans;
}
int  Buld(int l,int r){
	if(l==r)return New(a[l]);
	int mid=l+r>>1,now;
	now=merge(Buld(l,mid),Buld(mid+1,r));
	return now;
}
int main(){
	srand(time(0));
//	freopen("P2042_8.in","r",stdin);
//	freopen("ans.out","w",stdout);
//	double st=clock();
	n=read();T=read();
	for(int i=1;i<=n;i++){
		int x;
		x=read();
		rt=merge(rt,New(x));
	}
	while(T--){
		char op[30];
		scanf("%s",op);
		int w,c,x;
		if(op[0]=='I'){
			w=read();c=read();
			int TpT=0;
			for(int i=1;i<=c;i++)a[i]=read();
			TpT=Buld(1,c);
			int x,y,z;
			split(rt,w,x,y);
			rt=merge(merge(x,TpT),y);
		}
		else if(op[0]=='D'){
			w=read();c=read();
			del(w,w+c-1);
		}
		else if(op[2]=='K'){
			w=read();c=read();x=read();
			modify(w,w+c-1,x);
		}
		else if(op[0]=='R'){
			w=read();c=read();
			reverse(w,w+c-1);
		}
		else if(op[0]=='G'){
			w=read();c=read();
			printf("%d\n",qsum(w,w+c-1));
		}
		else if(op[0]=='M')printf("%d\n",dat[rt]);
	}
	//cout<<clock()-st;
	return 0;
}
posted @ 2021-02-01 13:41  Isenthalpic  阅读(388)  评论(0编辑  收藏  举报