首页 > 技术文章 > POJ 2750 Potted Flower 线段树区间合并

fenshen371 2013-07-24 11:27 原文

题目大意:一个圆环上有n(4<= n <= 100000)个数字,编号依次从1到n,第n个数与第1个数相连。规则是:从环上选取任意个数(但不能为0也不能取全部)的连续数字,使选取数字之和最大。但现在有m(4<= m <= 100000)个操作,用a, b两个数字来描述, 意思是:将环上编号为a的数字换成b。现要求每次操作后都按照规则输出最大之和。更多细节点击传送门

思路:因为查询次数太大,用线段树来维护数据。将圆环从编号为1和n的数字间断开,扯成直线。因不能选择全部数字的限制,将情况分成两种。

1. 圆环上的数全是正数。所有数字之和减去其中最小的一个数,即为结果。

2. 圆环上的数有负数。此时有两种选取数字的方式:

  1. 所选的连续数字包含编号1和n的两个数。此时在线段树内他们并不连续(在1和n之间被断开了)。所有数字之和减去线段树区间内数字最小之和即为结果。

  2. 所选的连续数字不包含1和n两个数。用线段树维护出区间内最大连续数字之和即可。

线段树需要维护7个数据:sum, lmax, rmax, tmax, lmin, rmin, tmin。

其中lmax意为从区间左端第一个数开始的最大连续数字之和,rmax意为从区间右端第一个数开始的最大连续数字之和,tmax意为整个区间的最大连续数字之和。 min同理。

至于条件判定,当圆环上全是正数时,对于整个区间有sum=tmax。

各区间合并的具体公式见代码中PushUp函数。

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #define maxn 100010
 4 #define lson l, m, rt << 1
 5 #define rson m + 1, r, rt << 1 | 1
 6 using namespace std;
 7 int sum[maxn<<2], lmax[maxn<<2], rmax[maxn<<2], tmax[maxn<<2];
 8 int lmin[maxn<<2], rmin[maxn<<2], tmin[maxn<<2];
 9 void PushUp(int rt)
10 {
11     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
12     lmax[rt] = max(lmax[rt<<1], sum[rt<<1] + lmax[rt<<1|1]);
13     rmax[rt] = max(rmax[rt<<1|1], sum[rt<<1|1] + rmax[rt<<1]);
14     tmax[rt] = max(tmax[rt<<1], max(tmax[rt<<1|1], rmax[rt<<1] + lmax[rt<<1|1]));
15     lmin[rt] = min(lmin[rt<<1], sum[rt<<1] + lmin[rt<<1|1]);
16     rmin[rt] = min(rmin[rt<<1|1], sum[rt<<1|1] + rmin[rt<<1]);
17     tmin[rt] = min(min(tmin[rt<<1], tmin[rt<<1|1]), rmin[rt<<1] + lmin[rt<<1|1]);
18 }
19 void build(int l,int r,int rt)
20 {
21     if (l == r)
22     {
23         scanf("%d",&sum[rt]);
24         lmax[rt] = rmax[rt] = tmax[rt] = lmin[rt] = rmin[rt] = tmin[rt] = sum[rt];
25         return;
26     }
27     int m = (l + r) >> 1;
28     build(lson);
29     build(rson);
30     PushUp(rt);
31 }
32 void update(int a,int b,int l,int r,int rt)
33 {
34     if (l == r && l == a)
35     {
36         lmax[rt] = rmax[rt] = tmax[rt] = lmin[rt] = rmin[rt] = tmin[rt] = sum[rt] = b;
37         return;
38     }
39     int m = (l + r) >> 1;
40     if (a <= m) update(a, b, lson);
41     else update(a, b, rson);
42     PushUp(rt);
43 }
44 int main()
45 {
46     int n, m;
47     //freopen("data.in","r",stdin);
48     scanf("%d",&n);
49     build(1, n, 1);
50     scanf("%d",&m);
51     while (m--)
52     {
53         int a, b;
54         scanf("%d%d",&a,&b);
55         update(a, b, 1, n, 1);
56         if (sum[1] == tmax[1]) printf("%d\n",sum[1] - tmin[1]);
57         else printf("%d\n",max(tmax[1], sum[1] - tmin[1]));
58     }
59     return 0;
60 }

 

推荐阅读