题目大意:

有N盆花排成一圈,每盆花有一个吸引力值,然后有M次操作,每次可以把指定一盆花的吸引力值改成指定的数。输出每次操作后连续的一段吸引力最大的和,其中,N盆花不能全选、也不能不选。

算法讨论:

大概,这道题Zeyuan Zhu的目的是要考线段树的吧。可我正在学习splay,就找了这样一道简单些的线段树题目来做~

splay的基本知识,推荐2006年国家集训队杨思雨神牛(我的偶像之一)的论文,以及jzp教主的《运用伸展树解决数列维护问题》论文。

维护一棵splay,其中每个节点表示一盆花,其中每个节点记录这样几个关键字:size(这个节点所控制的数字数目)、value(这个节点的数值)、sum(这个节点控制范围的value和)、maxl(以这个节点为左端点能达到的最大值)、maxr(以这个节点为右端点能达到的最大值)、maxm(这个节点所控制的最大子段和)、minl(以这个节点为左端点能达到的最小值)、minr(以这个节点为右端点能达到的最小值)、minm(这个节点所控制的最小子段和)。

本题的关键是Update更新节点信息(具体参见代码)

求解时,只需要把整个 数列旋转到以root->ch[1]->ch[0]为根的地方,然后特判 root->ch[1]->ch[0]->minm是否大于等于0,如果是,则ans = root->ch[1]->ch[0]->sum - root->ch[1]->ch[0]->minm, 否则 ans = max(root->ch[1]->ch[0]->sum - root->ch[1]->ch[0]->minm, root->ch[1]->ch[0]->maxm),最后输出ans即可。

 参考代码:

  1 # include <cstdio>
2 # include <iostream>
3 using namespace std;
4 const int maxn = 200005;
5 struct Node{
6 long long size, maxm, maxl, maxr, minm, minl, minr, value, sum;
7 Node *ch[2], *pre;
8 } tree[maxn], *root, *Null;
9 int num[maxn], top = 0;
10
11 Node *NewNode(int limit)
12 {
13 Node *now;
14 now = &tree[top++];
15 now->size = 1, now->maxm = now->maxl = now->maxr = now->value = limit;
16 now->minm = now->minl = now->minr = now->sum = limit;
17 now->ch[1] = now->ch[0] = now->pre = Null;
18 return now;
19 }
20
21 long long max(long long i, long long j)
22 {
23 if (i>j) return i;return j;
24 }
25
26 long long min(long long i, long long j)
27 {
28 if (i<j) return i; return j;
29 }
30
31 void Update(Node *x)
32 {
33 if (x== Null) return;
34 x->size = x->ch[0]->size + x->ch[1]->size + 1;
35 x->sum = x->ch[0]->sum + x->ch[1]->sum + x->value;
36 x->maxl = max(x->ch[0]->maxl, x->ch[0]->sum + x->value + max(0, x->ch[1]->maxl));
37 x->maxr = max(x->ch[1]->maxr, x->ch[1]->sum + x->value + max(0, x->ch[0]->maxr));
38 x->maxm = max(x->ch[0]->maxm, x->ch[1]->maxm);
39 x->maxm = max(x->maxm, max(x->ch[0]->maxr, 0)+ x->value + max(x->ch[1]->maxl, 0));
40 if (x->ch[0] == Null) x->minl = x->value + min(0, x->ch[1]->minl); else
41 x->minl = min(x->ch[0]->minl, x->ch[0]->sum + x->value + min(0, x->ch[1]->minl));
42 if (x->ch[1] == Null) x->minr = x->value + min(0, x->ch[0]->minr); else
43 x->minr = min(x->ch[1]->minr, x->ch[1]->sum + x->value + min(0, x->ch[0]->minr));
44 if (x->ch[0] == Null)
45 if (x->ch[1] == Null) x->minm = x->value;
46 else x->minm = min(x->ch[1]->minm,x->value+min(x->ch[1]->minl, 0)); else
47 if (x->ch[1] == Null) x->minm = min(x->ch[0]->minm,x->value+min(x->ch[0]->minr, 0)); else{
48 x->minm = min(x->ch[0]->minm, x->ch[1]->minm);
49 x->minm = min(x->minm, min(x->ch[1]->minl, 0) + x->value + min(0,x->ch[0]->minr));
50 }
51 }
52
53 void Rotate(Node *x,int c)
54 {
55 Node *y = x->pre;
56 y->ch[!c] = x->ch[c], x->pre = y->pre;
57 if (x->ch[c] != Null) x->ch[c]->pre = y;
58 if (y->pre != Null) y->pre->ch[y->pre->ch[1] == y] = x;
59 y->pre = x, x->ch[c] = y;
60 if (y == root) root = x;
61 Update(y);
62 }
63
64 void splay(Node *x, Node *fa)
65 {
66 for ( ;x->pre != fa; ){
67 if (x->pre->pre == fa) Rotate(x, x->pre->ch[0] == x);
68 else{
69 Node *y = x->pre, *z = y->pre;
70 if (z->ch[0] == y){
71 if (y->ch[0] == x) Rotate(y,1), Rotate(x,1);
72 else Rotate(x,0), Rotate(x,1);
73 } else {
74 if (y->ch[1] == x) Rotate(y,0), Rotate(x,0);
75 else Rotate(x,1), Rotate(x,0);
76 }
77 }
78 }
79 Update(x);
80 }
81
82 void select(int k, Node *fa)
83 {
84 Node *now;
85 for (now = root; ; ){
86 int tmp = now->ch[0]->size;
87 if (tmp + 1 == k) break;
88 if (tmp >= k) now = now->ch[0];
89 else now = now->ch[1], k -= tmp+1;
90 }
91 splay(now, fa);
92 }
93
94 Node *Maketree(int l, int r, Node *fa)
95 {
96 if (l>r) return Null;
97 long long mid = l + r >> 1;
98 Node *now = NewNode(num[mid]);
99 now->ch[0] = Maketree(l,mid-1,now), now->ch[1] = Maketree(mid+1,r,now);
100 now->pre = fa, Update(now);
101 return now;
102 }
103
104 void Ins(int pos, int tot)
105 {
106 for (int i = 1; i <= tot; i++) scanf("%d",&num[i]);
107 select(pos,Null), select(pos+1,root);
108 root->ch[1]->ch[0] = Maketree(1,tot,root->ch[1]);
109 splay(root->ch[1]->ch[0], Null);
110 }
111
112 int main()
113 {
114 int n, m, a, b;
115 long long ans;
116 Null = NewNode(0), Null->size = 0;
117 root = NewNode(0), root->ch[1] = NewNode(0), root->ch[1]->pre = root, Update(root);
118 scanf("%d",&n), Ins(1,n), scanf("%d",&m);
119 while (m--){
120 scanf("%d%d",&a,&b), select(a,Null), select(a+2,root);
121 Node *now = root->ch[1]->ch[0];
122 now->value = now->sum = now->maxl = now->maxr = b;
123 now->maxm = now->minl = now->minr = now->minm = b;
124 splay(now,Null);
125 select(1,Null), select(n+2,root);
126 now = root->ch[1]->ch[0];
127 if (now->minm>=0) ans = now->sum - now->minm;
128 else ans = max(now->maxm, now->sum-now->minm);
129 printf("%d\n",ans);
130 }
131 return 0;
132 }