BZOJ 1500 [NOI2005]维修数列 Splay

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

Source



这题是splay里的魔鬼题了吧。。调了好久QAQ

最终在大牛help下AC(%%%)

对于操作1,首先构造一个x~y的区间(也就是split(x,y)分离过程),然后直接插入。

对于操作2,split(x,x+tot-1),然后将以对应区间为根的子树删除。

对于操作3,split出区间后,在子树的根上加一个tag来标记更新。

           值得注意的是,加上这个tag之后,就不需要rev(旋转)标记了。

对于操作4,同上,加一个rev标记。

对于操作5,在整棵树上的每一个点加上一个sum(),sum(u)=sum(L)+sum(R)+num(u),L和R是u儿子,

         如此维护即可。

对于操作6,略有麻烦。我们需要维护三个信息:一段区间的最大前缀lx,一段区间的最大后缀rx,

           以及一段区间本身的最大子列和mx(对了,子列是连续的);

           维护的方法:

                   mx(u)=max{mx(L),mx(R),rx(L)+lx(R)+num(u)}

                   lx(u)=max{lx(L),sum(L)+num(u)+lx(R)}

                   rx(u)=max(rx(R),sum(R)+num(u)+rx(L)}

注意一下此题4000000个数。。。但是序列里只会有500000个。。
所以可以考虑一下回收内存。。当然不回收也不会出什么事情。
不用快速读入bzoj上可能会挂(评测机器比较慢),所以还是加一下吧。

这种模板题还是要。。看代码吧(QAQ)


#include<bits/stdc++.h>
using namespace std;
const int
	NN=500000+5,
	MM=5000000+5,
	overroot=0;
int n,m,top,root;
int id[NN],a[NN],stk[MM];
struct Tree{
	int son[2],pre,sz,num,sum,mx,lx,rx;
	bool tag,rev;
}tree[NN];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void up(int u){
	if (u){
		int l=tree[u].son[0],r=tree[u].son[1];
		tree[u].sz=1+tree[l].sz+tree[r].sz;
		tree[u].sum=tree[u].num+tree[l].sum+tree[r].sum;
		tree[u].mx=max(tree[l].mx,tree[r].mx);
		tree[u].mx=max(tree[u].mx,tree[l].rx+tree[r].lx+tree[u].num);
		tree[u].lx=max(tree[l].lx,tree[l].sum+tree[r].lx+tree[u].num);
		tree[u].rx=max(tree[r].rx,tree[r].sum+tree[l].rx+tree[u].num);
	}
}
inline void down(int u){
	if (u){
		int l=tree[u].son[0],r=tree[u].son[1];
		if (tree[u].tag){
			tree[l].tag=1,tree[l].num=tree[u].num,tree[l].sum=tree[u].num*tree[l].sz;
			tree[r].tag=1,tree[r].num=tree[u].num,tree[r].sum=tree[u].num*tree[r].sz;
			if (tree[u].num>=0){
				tree[l].mx=tree[l].lx=tree[l].rx=tree[l].sum;
				tree[r].mx=tree[r].lx=tree[r].rx=tree[r].sum;
			}	else{
				tree[l].mx=tree[l].num;	tree[l].lx=tree[l].rx=0;
				tree[r].mx=tree[r].num;	tree[r].lx=tree[r].rx=0;
			}
			tree[u].tag=tree[u].rev=0;
		}
		if (tree[u].rev){
			swap(tree[l].son[0],tree[l].son[1]);
			swap(tree[r].son[0],tree[r].son[1]);
			swap(tree[l].lx,tree[l].rx);
			swap(tree[r].lx,tree[r].rx);
			tree[l].rev^=1;	tree[r].rev^=1;
			tree[u].rev=0;
		}
	}
}
int getkth(int x,int k){
	down(x);
	int tmp=tree[tree[x].son[0]].sz;
	if (tmp+1==k) return x;
	if (k<=tmp) return getkth(tree[x].son[0],k);
		else	return getkth(tree[x].son[1],k-tmp-1);
}
inline void Rotate(int x,int f){
	int y=tree[x].pre;
	tree[y].son[!f]=tree[x].son[f];
	tree[tree[x].son[f]].pre=y;
	tree[x].pre=tree[y].pre;
	if (tree[x].pre!=overroot) tree[tree[x].pre].son[tree[tree[x].pre].son[1]==y]=x;
	tree[x].son[f]=y;
	tree[y].pre=x;
	up(y);
}
void splay(int x,int goal){
	while (tree[x].pre!=goal){
		int y=tree[x].pre,z=tree[y].pre;
		down(z); down(y); down(x);
		if (z==goal) Rotate(x,tree[y].son[0]==x);
			else{
				int f=tree[z].son[0]==y;
				if (tree[y].son[f]==x) Rotate(x,!f);
					else Rotate(y,f);
				Rotate(x,f);
			}
	}
	up(x);
	if (goal==overroot) root=x;
}
inline int split(int a,int b){
	int x=getkth(root,a),
		y=getkth(root,b+2);
	splay(x,overroot);
	splay(y,x);
	return tree[tree[root].son[1]].son[0];
}
void del(int u){
	if (!u) return;
	stk[++top]=u;
	del(tree[u].son[0]);
	del(tree[u].son[1]);
	tree[u].son[0]=tree[u].son[1]=tree[u].pre=
		tree[u].tag=tree[u].rev=0;
}
int build(int l,int r){
	if (l>r) return 0;
	if (l==r){
		tree[id[l]].sum=tree[id[l]].num=a[l];
		tree[id[l]].sz=1;
		if (a[l]>=0) tree[id[l]].lx=tree[id[l]].rx=tree[id[l]].mx=a[l];
			else	tree[id[l]].lx=tree[id[l]].rx=0,tree[id[l]].mx=a[l];
		return l;
	}
	int mid=(l+r)>>1;
	tree[id[mid]].son[0]=id[build(l,mid-1)];
	tree[id[mid]].son[1]=id[build(mid+1,r)];
	int L=tree[id[mid]].son[0],R=tree[id[mid]].son[1];
	if (L) tree[L].pre=id[mid];
	if (R) tree[R].pre=id[mid];
	tree[id[mid]].num=a[mid];
	up(id[mid]);
	return mid;
}
void solve(){
	char t[11]; 
	scanf("%s",t);
	if (t[0]=='M' && t[1]=='A' && t[2]=='X'){
		printf("%d\n",tree[root].mx);
		return;
	}
	int x,y;
	if (t[0]=='G'){
		x=read(); y=read();
		x=split(x,x+y-1);
		printf("%d\n",tree[x].sum);
	}
	if (t[0]=='R'){
		x=read(); y=read();
		x=split(x,x+y-1);
		y=tree[x].pre;
		if (tree[x].tag) return;
		tree[x].rev^=1;
		swap(tree[x].lx,tree[x].rx);
		swap(tree[x].son[0],tree[x].son[1]);
		up(y); up(tree[y].pre); 
	}
	int tt;
	if (t[0]=='M'){
		x=read(); y=read(); tt=read();
		x=split(x,x+y-1);
		y=tree[x].pre;
		tree[x].tag=1; tree[x].num=tt;
		tree[x].sum=tt*tree[x].sz;
		if (tt>=0) tree[x].lx=tree[x].rx=tree[x].mx=tree[x].sum;
			else	tree[x].lx=tree[x].rx=0,tree[x].mx=tt;
		up(y); up(tree[y].pre);
		
	}
	if (t[0]=='D'){
		x=read(); y=read();
		x=split(x,x+y-1);
		y=tree[x].pre;
		del(x);
		tree[y].son[0]=0;
		up(y); up(tree[y].pre);
	}
	if (t[0]=='I'){
		x=read(); y=read();
		for (int i=1;i<=y;i++) a[i]=read();
		for (int i=1;i<=y;i++)
			if (top) id[i]=stk[top--];
				else id[i]=++n;
		int xx=getkth(root,x+1),yy=getkth(root,x+2);
		splay(xx,overroot); splay(yy,root);
		int tmp=id[build(1,y)];
		tree[yy].son[0]=tmp;
		tree[tmp].pre=yy;
		up(yy); up(xx);
	}
}
int main(){
	n=read(),m=read();
	tree[0].mx=a[1]=a[n+2]=-100000000;
	for (int i=1;i<=n;i++) a[i+1]=read();
	n+=2;
	for (int i=1;i<=n;i++) id[i]=i;
	root=build(1,n);
	while (m--) solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值