洛谷 P4513 小白逛公园

题目背景

小新经常陪小白去公园玩,也就是所谓的遛狗啦…

题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。

输入格式

第一行,两个整数NN和MM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来MM行,每行三个整数。第一个整数KK,11或22。

  • K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1a,bN)。测试数据可能会出现a>ba>b的情况,需要进行交换;
  • K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1pN)。
    其中,1≤N≤500 0001N500000,1≤M≤100 0001M100000,所有打分都是绝对值不超过10001000的整数。

输出格式

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

输入输出样例

输入 #1
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
输出 #1
2
-1
思路:不得不说这个题是一个好题,而且加深了我对线段树的理解,让我知道了线段树还能这么用。
其实这个题没想象中的难,个人感觉蓝题左右,难度不到紫题,洛谷评分虚高了一点。我这里用了一个技巧,用L表示区间左端点严格为线段树节点区间左端点的子序列最大值,R同理
s则是区间左右端点不加以限制的最大值(也就是题目要的答案)。显然线段树在合并信息的时候,L的值为:max{左子节点的L,左子节点sum加上右子节点的L},R同理,s则为
max{左子节点s,右子节点s,左子节点R与右子节点L的和}(想想为什么),然后按正常的线段树操作做即可。
没想象中的难。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N = 5e5 + 5;
 7 struct seg{
 8     int l, r;
 9     int sum, L, R, s;
10 }tr[N << 2];
11 int n, m, num[N];
12 #define ls p << 1
13 #define rs p << 1|1
14 #define inf 2e9
15 void update(int p)
16 {
17     tr[p].sum = tr[ls].sum + tr[rs].sum;
18     tr[p].L = max(tr[ls].L, tr[ls].sum + tr[rs].L);
19     tr[p].R = max(tr[rs].R, tr[rs].sum + tr[ls].R);
20     tr[p].s = max(max(tr[ls].s, tr[rs].s), tr[ls].R + tr[rs].L);
21 }
22 void build(int p, int l, int r)
23 {
24     tr[p].l = l;
25     tr[p].r = r;
26     if(l == r)
27     {
28         tr[p].sum = num[l];
29         tr[p].L = num[l];
30         tr[p].R = num[l];
31         tr[p].s = num[l];
32         return;
33     }
34     int mid = l + r >> 1;
35     build(ls, l, mid);
36     build(rs, mid + 1, r);
37     update(p);
38 }
39 void modify_set(int p, int pos, int v)
40 {
41     if(tr[p].l == tr[p].r)
42     {
43         tr[p].sum = v;
44         tr[p].L = v;
45         tr[p].R = v;
46         tr[p].s = v;
47         return;
48     }
49     int mid = tr[p].l + tr[p].r >> 1;
50     if(pos <= mid) modify_set(ls, pos, v);
51     else modify_set(rs, pos, v);
52     update(p);
53 }
54 seg query(int p, int l, int r)
55 {
56     if(l <= tr[p].l && r >= tr[p].r)
57     {
58         return tr[p];
59     }
60     int mid = tr[p].l + tr[p].r >> 1;
61     seg lz = (seg){0, 0, 0, -inf, -inf, -inf};
62     seg rz = (seg){0, 0, 0, -inf, -inf, -inf};
63     seg ret;
64     if(l <= mid) lz = query(ls, l, r);
65     if(r > mid) rz = query(rs, l, r);
66     ret.sum = lz.sum + rz.sum;
67     ret.L = max(lz.L, lz.sum + rz.L);
68     ret.R = max(rz.R, rz.sum + lz.R);
69     ret.s = max(max(lz.s, rz.s), lz.R + rz.L);
70     return ret;
71 }
72 int main()
73 {
74     scanf("%d%d", &n, &m);
75     for(int i = 1; i <= n; i ++)
76         scanf("%d", &num[i]);
77     build(1, 1, n);
78     int op, a, b;
79     while(m --)
80     {
81         scanf("%d%d%d", &op, &a, &b);
82         if(op == 1)
83         {
84             if(a > b) swap(a, b);
85             printf("%d
", query(1, a, b).s);
86         }
87         else modify_set(1, a, b);
88     }
89     return 0;
90 }

原文地址:https://www.cnblogs.com/loi-frank/p/12285257.html