poj 2750 Potted Flower

题目大意:给定一组数,这组数是首尾相连的,然后每次都修改这个数环的某个数值,求修改过后的这个环的最大连续子序列和,并且最大连续子序列长度不能等于整个环长。

解题思路:我们可以把环从任意一点断开,我们取从数组0位置断开拉直组成0,1,。。。。,n - 1,N个数。

当这个组数总和就是为最大连续子序列和时,满足条件的长度不等于整个环长的子序列和则为总和减去最小连续子序列。

否则,最大连续子序列为没跨越断点的最大子序列和,   和跨越了断点的的最大连续子序列和=序列总和 - 最小连续子序列。这两个里面的最大值

由于每次都要更新值,每次都得循环求值,所以我们用线段树来记录区间值,更新后只要返回根节点的最大连续子序列和就行了。这样更新查询时间就是logN的

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

struct node
{
	int sum, minv, maxv, lmax, lmin, rmax, rmin, l_index, r_index;
};

const int maxn = 100010;

node tree[3 * maxn];
int n, m, array[maxn];

void create(int l, int r, int index);
void update(int index);
void modify(int index, int pos, int val);

int main()
{
	
	int pos, val, ans;
	while(scanf("%d", &n) != EOF)
	{
		for(int i = 0; i < n; i++)
			scanf("%d", &array[i]);
		create(0, n - 1, 0);
		scanf("%d", &m);
		for(int i = 0; i < m; i++)
		{
			scanf("%d %d", &pos, &val);
			modify(0, pos - 1, val);
			if(tree[0].sum == tree[0].maxv)
				ans = tree[0].sum - tree[0].minv;
			else
				ans = max(tree[0].maxv, tree[0].sum - tree[0].minv);
			printf("%d\n", ans);
		}
	}
	
	return 0;
}

void create(int l, int r, int index)
{
	tree[index].l_index = l, tree[index].r_index = r;
	if(l == r)
	{
		tree[index].sum = tree[index].rmin = tree[index].lmin = array[l];
		tree[index].lmax = tree[index].rmax = tree[index].maxv = tree[index].minv = array[l];
		return;
	}
	int mid = (l + r) >> 1;
	create(l, mid, 2 * index + 1);
	create(mid + 1, r, 2 * index + 2);
	update(index);
}

void update(int index)
{
	tree[index].sum = tree[2 * index + 1].sum + tree[2 * index + 2].sum;
	tree[index].lmin = min(tree[2 * index + 1].lmin, tree[2 * index + 1].sum + tree[2 * index + 2].lmin);
	tree[index].rmin = min(tree[2 * index + 2].rmin, tree[2 * index + 2].sum + tree[2 * index + 1].rmin);
	tree[index].lmax = max(tree[2 * index + 1].lmax, tree[2 * index + 1].sum + tree[2 * index + 2].lmax);
	tree[index].rmax = min(tree[2 * index + 2].rmax, tree[2 * index + 2].sum + tree[2 * index + 1].rmax);
	
	tree[index].minv = min(min(tree[2 * index + 1].minv, tree[2 * index + 2].minv), tree[2 * index + 1].rmin + tree[2 * index + 2].lmin);
	tree[index].maxv = max(max(tree[2 * index + 1].maxv, tree[2 * index + 2].maxv), tree[2 * index + 1].rmax + tree[2 * index + 2].lmax);
}

void modify(int index, int pos, int val)
{
	if(tree[index].l_index == tree[index].r_index)
	{
		tree[index].sum = tree[index].rmin = tree[index].lmin = val;
		tree[index].lmax = tree[index].rmax = tree[index].maxv = tree[index].minv = val;
		return;
	}
	
	int mid = (tree[index].l_index + tree[index].r_index) >> 1;
	if(pos <= mid)
		modify(2 * index + 1, pos, val);
	else 
		modify(2 * index + 2, pos, val);
	
	update(index);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值