[NOI2005]维护数列

题目:BZOJ1500、洛谷P2042、Vijos P1835、codevs1758。

题目大意:
给你一个数列,实现以下操作。


解题思路:
非旋Treap维护数列即可。
前面5个都是基本的平衡树序列操作(第5个维护一个区间和即可)。
第6个要求最大子段和,则我们需要维护以当前节点为子树的子段和,当前子树的最大前缀和和最大后缀和,才能转移出正确的最大子段和。(具体如何维护详见代码)
对于旋转操作,需要把前缀和后缀交换一下。
还有要注意:
1. 内存不能开太大,会MLE,要回收被删除的节点。
2. 插入时不要一个一个merge,先按照笛卡尔树的建树方式建树(O(n)),然后直接merge根即可。

C++ Code:

#include<bits/stdc++.h>
inline int max(int a,int b){return a>b?a:b;}
inline void swap(int& a,int& b){int c=a;a=b,b=c;}
inline int readint(){
	int c=getchar(),d=0,b=0;
	for(;!isdigit(c);c=getchar())b=c=='-';
	for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0');
	return b?-d:d;
}
struct node{
	int ls,rs,s,lm,rm,sm,smx,rot,r,tag,sz;
	inline void Cng(int val){
		s=val;
		sm=sz*val;
		lm=rm=max(sm,0);
		smx=max(sm,s);
		tag=1;
	}
	inline void rev(){
		swap(ls,rs);
		swap(lm,rm);
		rot^=1;
	}
}a[500005];
struct Memory_pool{
	int p[500005],top;
	Memory_pool(){
		for(int i=1;i<=500004;++i)p[i]=i;
		top=500004;
	}
	inline int New(){return p[top--];}
	inline void Del(int x){p[++top]=x;}
}P;
int n,m,rt,sta[500005],top=0;
inline void pushdown(int x){
	if(a[x].rot){
		a[x].rot=0;
		if(a[x].ls)a[a[x].ls].rev();
		if(a[x].rs)a[a[x].rs].rev();
	}
	if(a[x].tag){
		a[x].tag=0;
		if(a[x].ls)a[a[x].ls].Cng(a[x].s);
		if(a[x].rs)a[a[x].rs].Cng(a[x].s);
	}
}
inline void update(int x){
	int ls=a[x].ls,rs=a[x].rs,s=a[x].s;
	if(ls&&rs){
		a[x].sz=a[ls].sz+a[rs].sz+1;
		a[x].sm=a[ls].sm+a[rs].sm+s;
		a[x].smx=max(a[ls].smx,a[rs].smx);
		a[x].smx=max(a[x].smx,a[ls].rm+s+a[rs].lm);
		a[x].lm=max(a[ls].lm,a[ls].sm+s+a[rs].lm);
		a[x].rm=max(a[rs].rm,a[rs].sm+s+a[ls].rm);
	}else
	if(ls){
		a[x].sz=a[ls].sz+1;
		a[x].sm=a[ls].sm+s;
		a[x].smx=max(a[ls].smx,a[ls].rm+s);
		a[x].lm=max(a[ls].lm,a[ls].sm+s);
		a[x].rm=max(a[ls].rm+s,0);
	}else
	if(rs){
		a[x].sz=a[rs].sz+1;
		a[x].sm=a[rs].sm+s;
		a[x].smx=max(a[rs].smx,a[rs].lm+s);
		a[x].rm=max(a[rs].rm,a[rs].sm+s);
		a[x].lm=max(a[rs].lm+s,0);
	}else{
		a[x].sz=1;
		a[x].sm=a[x].smx=s;
		a[x].lm=a[x].rm=max(s,0);
	}
}
int build(int n){
	int x,pre;
	for(int i=1;i<=n;++i){
		int f=readint();
		int ff=max(f,0);
		a[x=P.New()]=(node){0,0,f,ff,ff,f,f,0,rand(),0,1};
		for(pre=0;top&&a[sta[top]].r>a[x].r;--top)update(pre=sta[top]);
		if(top)a[sta[top]].rs=x;
		a[sta[++top]=x].ls=pre;
	}
	while(top)update(sta[top--]);
	return sta[1];
}
void split(int u,int k,int& x,int& y){
	if(!k){
		x=0,y=u;
		return;
	}
	if(k==a[u].sz){
		x=u,y=0;
		return;
	}
	pushdown(u);
	if(a[a[u].ls].sz>=k)split(a[u].ls,k,x,a[u].ls),y=u;else
	split(a[u].rs,k-a[a[u].ls].sz-1,a[u].rs,y),x=u;
	update(u);
}
int merge(int x,int y){
	if(x)pushdown(x);
	if(y)pushdown(y);
	if(!x||!y)return x|y;
	if(a[x].r<a[y].r){
		a[x].rs=merge(a[x].rs,y);
		update(x);
		return x;
	}
	a[y].ls=merge(x,a[y].ls);
	update(y);
	return y;
}
void dispose(int now){
	if(!now)return;
	dispose(a[now].ls);
	dispose(a[now].rs);
	P.Del(now);
}
int main(){
	n=readint(),m=readint();
	a[0]=(node){0,0,0,0,0,0,0,0,0,0,0};
	srand(20170607);
	rt=build(n);
	while(m--){
		static char s[100];
		int tot;
		scanf("%s",s);
		if(s[0]=='I'){
			tot=readint();int rtn=build(readint()),x,y;
			split(rt,tot,x,y);
			rt=merge(merge(x,rtn),y);
		}else
		if(s[0]=='D'){
			tot=readint(),n=readint();
			int x,y,z;
			split(rt,tot-1,x,y);
			split(y,n,y,z);
			dispose(y);
			rt=merge(x,z);
		}else
		if(s[0]=='M'&&s[2]=='K'){
			tot=readint(),n=readint();
			int x,y,z;
			split(rt,tot-1,x,y);
			split(y,n,y,z);
			a[y].Cng(readint());
			rt=merge(merge(x,y),z);
		}else
		if(s[0]=='R'){
			tot=readint(),n=readint();
			int x,y,z;
			split(rt,tot-1,x,y);
			split(y,n,y,z);
			a[y].rev();
			rt=merge(merge(x,y),z);
		}else
		if(s[0]=='G'){
			tot=readint(),n=readint();
			int x,y,z;
			split(rt,tot-1,x,y);
			split(y,n,y,z);
			printf("%d
",a[y].sm);
			rt=merge(merge(x,y),z);
		}else printf("%d
",a[rt].smx);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/8876703.html