poj2750-Potted Flower-动态求最大连续环区间和(线段树上分治+set维护)

http://poj.org/problem?id=2750

题意,给你n个数,首尾相接,让你求最大连续环区间和

首先知道这个最大连续和只有两种情况,

1是不跨越首尾的,这种直接求

2是跨越首尾的,显然最大连续和是跨越首尾的,那么最小连续区间和必然在1-n之间,所以我们只需要求最小连续和,然后sum-它就得到最大连续和


如果只求一次,可以dp就好了,但是由于每次动态更新单点,所以得用分治法求,在线段树上维护 

一个区间的 最大连续和,最小连续和,最大连续前缀/后缀,最小连续前缀/后缀,区间和,共七个值(或许可以维护少几个。。。)


然后每次单点更新后,1是查询maxx[1],而是sum[1]-minn[1]。


注意是,题目要求不能把所有点都选上,所以如果是 1111的情况,只能选3个。

也就是如果最后maxx_ans==sum【1】,的话我们就删掉一个最小的值


这个最小值 我用set+一个vis数组维护。。直接用multiset也应该OK

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map> 
#include <vector>
#include <iostream>
using namespace std; 
#define ll int
const double pi=acos(-1.0);
double eps=1e-5;    
int max(int a,int b)
{return a>b?a:b;}
int min(int a,int b)
{return a<b?a:b;}
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int n,m;
const int maxn=100000+50; 
int tm[maxn];
struct tree
{
	int maxx[maxn<<2];
	int suf_maxx[maxn<<2];
	int pre_maxx[maxn<<2];
	int pre_minn[maxn<<2];
	int suf_minn[maxn<<2];
	int minn[maxn<<2];
	int sum[maxn<<2];
	void PushUP(int rt)
	{ 
		sum[rt] =sum[rt<<1]+sum[rt<<1|1];
		maxx[rt] =max(  maxx[rt<<1],maxx[rt<<1|1]);
		maxx[rt]=max(maxx[rt],suf_maxx[rt<<1]+pre_maxx[rt<<1|1]);
		
		suf_maxx[rt] =max(suf_maxx[rt<<1]+sum[rt<<1|1],suf_maxx[rt<<1|1]);
		pre_maxx[rt] =max(pre_maxx[rt<<1|1]+sum[rt<<1],suf_maxx[rt<<1]);
		
		minn[rt] =min(  minn[rt<<1],minn[rt<<1|1]);
		minn[rt]=min(minn[rt],suf_minn[rt<<1]+pre_minn[rt<<1|1]);
		
		pre_minn[rt]=min(pre_minn[rt<<1],sum[rt<<1]+pre_minn[rt<<1|1]);
		suf_minn[rt]=min(suf_minn[rt<<1|1],sum[rt<<1|1]+suf_minn[rt<<1]);
	} 
	void build(int l,int r,int rt)
	{
		if (l == r)
		{	
			sum[rt]=pre_minn[rt]=suf_minn[rt]=suf_maxx[rt]=pre_maxx[rt]=minn[rt]=maxx[rt]=tm[r];
			
			return ;
		}
		int m = (l + r) >> 1;
		build(lson);
		build(rson);
		PushUP(rt);
	}
	
	void update(int l,int r,int rt,int num,int val) 
	{
		if (l == r&& r==num)
		{    
			sum[rt]=pre_minn[rt]=suf_minn[rt]=suf_maxx[rt]=pre_maxx[rt]=minn[rt]=maxx[rt]=val;  
			return ;
		}
		int m = (l + r) >> 1;
		if (num<=m)
			update(lson,num,val);
		else
			update(rson,num,val);
		
		PushUP(rt);
	}  
};

tree tp;
int vis[3000];
set<int> sb;
int main()
{  
	int	i ;
		  int n;
		  cin>>n;
		  int minnnn=10000; 
		  for (i=1;i<=n;i++) 
		  {
			  scanf("%d",&tm[i]); 
			   vis[tm[i]+1000]++;
			   if (vis[tm[i]+1000]==1)
				   sb.insert(tm[i]);
		  }
		  tp.build(1,n,1);
		  cin>>m;
		  int who,val;
		  for (i=1;i<=m;i++) 
		  { 
			  scanf("%d%d",&who,&val);  
			  tp.update(1,n,1,who,val);	//更新val  
			  vis[tm[who]+1000]--;		//删除tm[who]
			  if (vis[tm[who]+1000]==0)	//如果数量为零,从set抹除
				sb.erase(tm[who]);		
			  vis[val+1000]++;			//增加val个数,如果是第一次,加入set
			  if (vis[val+1000]==1)	
				  sb.insert(val);		
			  tm[who]=val;				//更新tm[who]

			  int ret_maxx=tp.maxx[1];
			  int ret_minn=tp.minn[1];
			  ret_minn =tp.sum[1]-ret_minn ;
			  int ans=max(ret_maxx,ret_minn);
			  if (ans==tp.sum[1]) 
				  ans-=*(sb.begin());
			  printf("%d\n",ans);
		  } 
		  return 0; 
}



你可能感兴趣的:(poj2750-Potted Flower-动态求最大连续环区间和(线段树上分治+set维护))