BZOJ 1500([NOI2005]维修数列-Splay的数列维护)

1500: [NOI2005]维修数列

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 3087   Solved: 920
[ Submit][ Status][ Discuss]

Description

Input

输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。 第2行包含N个数字,描述初始时的数列。 以下M行,每行一条命令,格式参见问题描述中的表格。

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

Splay解决数列维护。

推荐:用伸展树解决数列维护问题


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (500000+10)
#define MAXM (20000+10)
#define INF (0xfffffff)
struct node
{
	int value,MaxL,MaxR,MaxM,sum,size;
	bool rev,same;
	node *ch[2],*pre;
	node(node *f,int _value,int _MaxL,int _MaxR,int _MaxM,int _sum,int _size):value(_value),MaxL(_MaxL),MaxR(_MaxR),MaxM(_MaxM),sum(_sum),size(_size){rev=same=0,pre=f,ch[0]=ch[1]=NULL;}
	node(){rev=same=0;}
	int l_siz(){if (ch[0]) return ch[0]->size;else return 0;}
//	int r_siz(){return (ch[1])?ch[1]->size:0;}
	
	friend void pushdown(node *x)
	{
		if (x)
		{
			if (x->rev)
			{
				x->rev=0;
				if (x->ch[0]) x->ch[0]->rev^=1;
				if (x->ch[1]) x->ch[1]->rev^=1;
				swap(x->ch[0],x->ch[1]);
				swap(x->MaxL,x->MaxR);
			}
			if (x->same)
			{
				x->same=0;
				if (x->ch[0]) {x->ch[0]->same=1;x->ch[0]->value=x->value;x->ch[0]->sum=x->value*x->ch[0]->size;x->ch[0]->MaxL=x->ch[0]->MaxR=x->ch[0]->MaxM=max(x->value,x->ch[0]->sum);}
				if (x->ch[1]) {x->ch[1]->same=1;x->ch[1]->value=x->value;x->ch[1]->sum=x->value*x->ch[1]->size;x->ch[1]->MaxL=x->ch[1]->MaxR=x->ch[1]->MaxM=max(x->value,x->ch[1]->sum);}
			}
		}
	}
	friend void update(node *x)
	{
		if (x)
		{
			pushdown(x->ch[0]);pushdown(x->ch[1]); //由于有坑爹的rev操作,必须先down. 
			x->size=((x->ch[0])?x->ch[0]->size:0)+((x->ch[1])?x->ch[1]->size:0)+1;
			x->sum=((x->ch[0])?x->ch[0]->sum:0)+((x->ch[1])?x->ch[1]->sum:0)+x->value;
			x->MaxL=max(((x->ch[0])?x->ch[0]->MaxL:x->value),((x->ch[0])?x->ch[0]->sum:0)+x->value+max(0,((x->ch[1])?x->ch[1]->MaxL:0)));
			x->MaxR=max(((x->ch[1])?x->ch[1]->MaxR:x->value),((x->ch[1])?x->ch[1]->sum:0)+x->value+max(0,((x->ch[0])?x->ch[0]->MaxR:0)));
		//	cout<<((x->ch[1])?x->ch[1]->MaxR:x->value)<<' '<<+max(0,(((x->ch[0])?x->ch[0]->MaxR:0)))<<endl;
			x->MaxM=max(max(((x->ch[0])?x->ch[0]->MaxM:x->value),((x->ch[1])?x->ch[1]->MaxM:x->value)),((x->ch[0])?max(x->ch[0]->MaxR,0):0)+((x->ch[1])?max(x->ch[1]->MaxL,0):0)+x->value);
		}
	}
};
node *q[MAXN];
int q_siz=0;
int n,m,a[MAXN];
node* newnode(node *f,int value,int MaxL,int MaxR,int MaxM,int sum,int size)
{
	if (q_siz)
	{
		q[q_siz]->value=value;
		q[q_siz]->MaxL=MaxL;
		q[q_siz]->MaxR=MaxR;
		q[q_siz]->MaxM=MaxM;
		q[q_siz]->sum=sum;
		q[q_siz]->size=size;
		q[q_siz]->rev=q[q_siz]->same=0;q[q_siz]->pre=f;q[q_siz]->ch[0]=q[q_siz]->ch[1]=NULL;
		return q[q_siz--];
	}
	node *x=new node(f,value,MaxL,MaxR,MaxM,sum,size);
	return x;	
}
node* newnode()
{
	if (q_siz) return q[q_siz--];
	node *x=new node();
	return x;
}
void addnode(node *x)
{
	q[++q_siz]=x;
	*x=node();
}
struct Splay
{
	node *root;
	Splay()
	{
		root=newnode(NULL,-INF,-INF,-INF,-INF,0,2);
		root->ch[0]=newnode(root,-INF,-INF,-INF,-INF,0,1);
	}
	void Print(node *x)
	{
		if (x->ch[0]) {cout<<"(",Print(x->ch[0]),cout<<")-";}
		cout<<x->same;
		if (x->ch[1]) cout<<"-(",Print(x->ch[1]),cout<<")";
	}
	void rotate(node *x,int c) //0左旋 1右旋 
	{
		node *y=x->pre;
		pushdown(y),pushdown(x);
		y->ch[!c]=x->ch[c];
		if (x->ch[c]!=NULL) x->ch[c]->pre=y;
		x->pre=y->pre;
		if (y->pre!=NULL)
		{
			if (y->pre->ch[0]==y) y->pre->ch[0]=x;
			else y->pre->ch[1]=x;
		}
		x->ch[c]=y;y->pre=x;
		if (y==root) root=x;
		update(y);
	}
	void splay(node *x,node *f)
	{
		for(pushdown(x);x->pre!=f;)
		{
			if (x->pre->pre==f)
			{
				if (x->pre->ch[0]==x) rotate(x,1);
				else rotate(x,0);
			}
			else
			{
				node *y=x->pre,*z=y->pre;
				pushdown(z);pushdown(y);pushdown(x); //rev改变树结构 
				if (y->ch[0]==x&&z->ch[0]==y) rotate(y,1),rotate(x,1);
				else if (y->ch[1]==x&&z->ch[1]==y) rotate(y,0),rotate(x,0);
				else if (y->ch[0]==x&&z->ch[1]==y) rotate(x,1),rotate(x,0);
				else if (y->ch[1]==x&&z->ch[0]==y) rotate(x,0),rotate(x,1);
			}	
			update(x);
			//Print(root);cout<<endl;
		}
	} 
	node* find_kth(node *x,int k)
	{
		pushdown(x); //确保x正确 
		if (x->l_siz()>=k) return find_kth(x->ch[0],k);
		if (x->l_siz()+1==k) return x;
		else return find_kth(x->ch[1],k-x->l_siz()-1);
	}
	void build(node *f,node *x,int l,int r)
	{
		if (l>r) return;
		int m=(l+r)>>1;
		*x=node(f,a[m],a[l],a[r],a[m],a[m],1);
		if (l<m) build(x,x->ch[0]=newnode(),l,m-1);
		if (m<r) build(x,x->ch[1]=newnode(),m+1,r);
		if (l<r) update(x);
	}
	void del(node *x)
	{
		if (x->ch[0]) del(x->ch[0]);
		if (x->ch[1]) del(x->ch[1]);
		addnode(x);
	}
	void insert(int pos,int tot)
	{
		splay(find_kth(root,pos+1),NULL);
		splay(find_kth(root,pos+2),root);
		root->ch[1]->ch[0]=newnode();
		build(root->ch[1],root->ch[1]->ch[0],1,tot);
		update(root->ch[1]);update(root);
	}
	void delet(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);
		del(root->ch[1]->ch[0]);
		root->ch[1]->ch[0]=NULL;
		update(root->ch[1]);update(root);
	}
	void reverse(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		root->ch[1]->ch[0]->rev^=1;
		update(root->ch[1]);update(root);
	}
	void make_same(int pos,int tot,int c)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		node *x=root->ch[1]->ch[0];
		x->same=1;
		x->value=c;
		x->sum=c*x->size;
		x->MaxL=x->MaxR=x->MaxM=max(x->value,x->sum);
		update(root->ch[1]);update(root);
	}
	void get_sum(int pos,int tot)
	{
		if (tot==0)
		{
			printf("0\n");
			return;
		}
		splay(find_kth(root,pos),NULL);
		//Print(root);cout<<endl;
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);cout<<endl;
		node *x=root->ch[1]->ch[0];
		printf("%d\n",x->sum);
	}	
	void max_sum()
	{
		splay(find_kth(root,1),NULL);
		splay(find_kth(root,root->size),root);
		printf("%d\n",root->ch[1]->ch[0]->MaxM);
	}
}S;
int main()
{
//	freopen("bzoj1500.in","r",stdin);
	cin>>n>>m;
	for (int i=1;i<=n;i++) cin>>a[i];
	S.insert(0,n);
	//S.Print(S.root);cout<<endl;
	for (int i=1;i<=m;i++)
	{
	//	cout<<i<<':';
		char s[10];
		scanf("%s",s);
		switch (s[2])
		{
			case'S':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					for (int i=1;i<=tot;i++) scanf("%d",&a[i]);
					S.insert(pos,tot);
					break;
				}
			case'L':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.delet(pos,tot);
					break;
				}
			case'K':
				{
					int pos,tot,c;
					scanf("%d%d%d",&pos,&tot,&c);
					S.make_same(pos,tot,c);
					break;
				}
			case'V':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.reverse(pos,tot);
					break;
				}
			case'T':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.get_sum(pos,tot);
					break;
				}
			case'X':
				{
					S.max_sum();
					break;
				}
		}
		//S.Print(S.root);cout<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值