POJ2750 Potted Flower (线段树+动态规划)

题目链接:传送门
 
题意:题目的意思是说在一个环形的盆中选取连续的子区间使得价值/吸引力最大,然后我们有一种操作即将花盆A的吸引力替换为B(单点修改),然后每次修改输出吸引力的最大价值

解题思路:把环从一个地方切断,使得环称为一条直线,用线段树记录当前区间的非空最大子列和非空最小子列,如果换上的数都是正数那么直接输出环的总价值-最小价值的盆,否则,输出\(Max(根节点的非空子列的总价值,环的总价值-根节点的非空最小价值的子列)\)
我们需要存储一下信息
ps:结点[a,m],[m+1,b]分别是root的左右儿子区间
Maxkey[N<<2],minkey[N<<2]//分别表示最大连续子列的价值和
lmax[N<<2],rmax[N<<2]//分别表示结点[a,b]包含a的最大连续子列价值和,结点[a,b]包含b的最大连续子列价值和
lmin[N<<2],rmin[N<<2]//分别表示结点[a,b]包含a的最小连续子列价值和,结点[a,b]包含b的最小连续子列价值和
sum[N<<2]//结点[a,b]的价值和
我们设父亲结点为k,左右子节点分别为l,r我们可以得出状态转移方程:
\(maxkey[k] = max(max(maxkey[l],maxkey[r]),rmax[l] + lmax[r])\)
\(minkey[k] = min(min(minkey[l],minkey[r]),rmin[l] + lmin[r])\)
\(lmax[k] = max(lmax[l],sum[l]+lmax[r])\)
\(rmax[k] = max(rmax[r],sum[r]+rmax[l])\)
\(lmin[k] = min(lmin[l],sum[l]+lmin[r])\)
\(rmin[k] = min(rmin[r],sum[r]+rmin[l])\)
 
Code:

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f3f;
const int N = 100005;
int a[N],tree[N],lazy[N];
int sum[N<<2],maxkey[N<<2],minkey[N<<2];
int lmax[N<<2],rmax[N<<2];
int lmin[N<<2],rmin[N<<2];

void pushup(int k) {
	int l = k << 1;
	int r = k << 1 | 1;
	sum[k] = sum[l] + sum[r];
	maxkey[k] = max(max(maxkey[l],maxkey[r]),rmax[l] + lmax[r]);
	minkey[k] = min(min(minkey[l],minkey[r]),rmin[l] + lmin[r]);
	lmax[k] = max(lmax[l],sum[l]+lmax[r]);
	rmax[k] = max(rmax[r],sum[r]+rmax[l]);
	lmin[k] = min(lmin[l],sum[l]+lmin[r]);
	rmin[k] = min(rmin[r],sum[r]+rmin[l]);
}

void build(int l,int r,int k) {
	if(l == r) {
		maxkey[k] = minkey[k] = lmax[k] = rmax[k] = lmin[k] = rmin[k] = sum[k] = a[l];
	}
	else {
		int mid = l + ((r - l) >> 1);
		build(l,mid,k<<1);
		build(mid+1,r,k<<1|1);
		pushup(k);
	}
}

void updata(int p,int v,int l,int r,int k) {
	if(l == r) {
		sum[k] = maxkey[k] = minkey[k] = v;
        lmax[k] = rmax[k] = lmin[k] = rmin[k] = v;
	}
	else {
		int mid = l + ((r - l) >> 1);
		if(p <= mid) {
			updata(p,v,l,mid,k<<1);
		}
		else {
			updata(p,v,mid+1,r,k<<1|1);
		}
		pushup(k);
	}
}


int main()
{
	int n,m;
	int u,v;
	scanf("%d",&n);
	for(int i = 1;i <= n; ++i) {
		scanf("%d",&a[i]);
	}
	build(1,n,1);
	scanf("%d",&m);
	while(m--) {
		scanf("%d%d",&u,&v);
		updata(u,v,1,n,1);
		int ans;
		if(sum[1] == maxkey[1])
			ans = sum[1] - minkey[1];
		else
			ans = max(maxkey[1],sum[1] - minkey[1]);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2021-01-18 21:06  MangataTS  阅读(82)  评论(0编辑  收藏  举报