【POJ2750】最大连续和

【POJ2750】最大连续和

Description

给出一个含有N个结点的环,编号分别为1..N,环上的点带有权值(可正可负),现要动态的修改某个点的权值,求每次修改后环上的最大连续和,但不能是整个序列的和。

Input

第一行为一个整数N(4<=N<=100000);
第二行为N个用空格分开的整数;
第三行为一个整数M(4<=M<=100000),表示修改的次数(绝对值小于等于1000);
接下来M行,每行两个整数A和B(-1000<=B<=1000),表示将序列中的第A个数的值,修改为B。

Output

对于每个修改,输出修改后环上的最大连续和。

Sample Input

5

3 -2 1 2 -5

4

2 -2

5 -5

2 -4

5 -1

Sample Output

4

4

3

5

Solution

        给定一个环,要求维护这个环上的最大连续和,只有修改操作。

        我们首先分析在没有修改的情况下的最大连续和。一个环上的最大连续和就是1~n序列的最大连续和与总和减去1~n序列的最小连续和中的最大值。对于得出的答案恰好等于总和的情况,我们将总和减去最小连续和就是答案了。

CODE

非常尴尬的写了Splay。。。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline int read(){
	char c;int rec=0,f=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;
	while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
	return rec*f;
}
int root,cnt,c[100005];
int n,m,V;
struct Splay_Tree{
	int F,s[2],size,val;
	int sum,maxx,minn,pmax[2],pmin[2];
	inline void NewNode(int fa,int x){
		F=fa;val=sum=maxx=minn=pmax[0]=pmax[1]=pmin[0]=pmin[1]=x;size=1;s[0]=s[1]=0;return ;
	}
}tree[100005];
inline void PMAX(int v,int f){
	tree[v].pmax[f]=max(tree[tree[v].s[f]].pmax[f],
	                tree[tree[v].s[f]].sum+tree[v].val+max(0,tree[tree[v].s[!f]].pmax[f]));
}
inline void PMIN(int v,int f){
	tree[v].pmin[f]=min(tree[tree[v].s[f]].pmin[f],
	                tree[tree[v].s[f]].sum+tree[v].val+min(0,tree[tree[v].s[!f]].pmin[f]));
}
inline void Pushup(int v){
	tree[v].size=tree[tree[v].s[0]].size+1+tree[tree[v].s[1]].size;
	tree[v].sum=tree[tree[v].s[0]].sum+tree[v].val+tree[tree[v].s[1]].sum;
	tree[v].maxx=max(max(tree[tree[v].s[0]].maxx,tree[tree[v].s[1]].maxx),
	        max(0,tree[tree[v].s[0]].pmax[1])+tree[v].val+max(0,tree[tree[v].s[1]].pmax[0]));
	PMAX(v,0);PMAX(v,1);
	tree[v].minn=min(min(tree[tree[v].s[0]].minn,tree[tree[v].s[1]].minn),
	        min(0,tree[tree[v].s[0]].pmin[1])+tree[v].val+min(0,tree[tree[v].s[1]].pmin[0]));
	PMIN(v,0);PMIN(v,1);
	return ;
}
inline void Rotate(int v){
	int p=tree[v].F,g=tree[p].F;
	int f1=(v==tree[p].s[1]),f2=(p==tree[g].s[1]),S=tree[v].s[!f1];
	tree[g].s[f2]=v;tree[v].F=g;
	tree[p].s[f1]=S;tree[S].F=p;
	tree[v].s[!f1]=p;tree[p].F=v;
	Pushup(p);return ;
}
inline void Splay(int v,int goal){
	while(tree[v].F!=goal){
		int p=tree[v].F,g=tree[p].F;
		if(g!=goal)(v==tree[p].s[1])^(p==tree[g].s[1])?Rotate(v):Rotate(p);
		Rotate(v);
	}Pushup(v);if(!goal)root=v;
	return ;
}
inline int Build(int L,int R,int fa){
	if(L>R)return 0;
	int mid=(L+R)>>1,p=++cnt;
	tree[p].NewNode(fa,c[mid]);
	tree[p].s[0]=Build(L,mid-1,p);
	tree[p].s[1]=Build(mid+1,R,p);
	Pushup(p);return p;
}
inline void Kth(int k){
	int v=root;
	while(tree[tree[v].s[0]].size+1!=k){
		if(tree[tree[v].s[0]].size+1>k)v=tree[v].s[0];
		else {k-=tree[tree[v].s[0]].size+1;v=tree[v].s[1];}
	}V=v;return ;
}
inline void Pre(int x,int y){Kth(x);Splay(V,0);Kth(y);Splay(V,root);return ;}
inline void Change(int x,int y){Pre(x-1,x+1);tree[tree[V].s[0]].NewNode(V,y);Pushup(V);Pushup(root);return ;}
int main(){
	n=read();
	int i,x,y;
	for(i=1;i<=n;i++)c[i]=read();
	tree[++cnt].NewNode(0,0);
	tree[++cnt].NewNode(1,0);
	tree[1].s[1]=2;root=1;
	tree[2].s[0]=Build(1,n,2);
	m=read();
	for(i=1;i<=m;i++){
		x=read();y=read();x++;Change(x,y);
		if(tree[root].maxx==tree[root].sum){cout<<tree[root].maxx-tree[root].minn<<'\n';}
		else cout<<max(tree[root].maxx,tree[root].sum-tree[root].minn)<<'\n';
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值