TYVJ1427 小白逛公园
【题目描述】
小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a、b两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
【输入文件】
第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。 接下来一行N个整数,依次给出小白开始时对公园的打分。
接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,小新要带小白出去玩,接下来的两个整数a和b给出了选择公园的范围(1≤a,b≤N);K=2表示,小白改变了对某个公园的打分,接下来的两个整数p和s,表示小白对第p个公园的打分变成了s(1≤p≤N)
其中,1≤N≤500 000,1≤M≤100 000,所有打分都是绝对值不超过1000的整数。
【输出文件】
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
【输入样例】
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
【输出样例】
2
-1
【题目分析】
我们知道,求一段序列的最大子段和是O(n)的,但是这样是显然会超时的。
我们需要一个数据结构来支持修改和计算的操作,对于这种修改一个而查询区间的问题,考虑使用线段树。
在线段树中,除了左端点,右端点,左儿子指针,右儿子指针之外,新开4个域——max,maxl,maxr,sum,其中sum为该区间的和,max为该区间上的最大子段和,maxl为必须包含左端点的最大子段和,maxr为必须包含右端点的最大子段和。
然后就……可以用线段树来统计了,注意求得的最大子段和中至少包含1个元素,所以出现了样例那样的输出负值。
修改时:
1、若左儿子的maxr和右儿子的maxl都为负,就从中取较大的为该节点的max(防止一个都不取),反之取二者中正的(都正就都取)。
2、将该节点的max用左右儿子的max更新。
3、该节点的maxl为左儿子的maxl与左儿子sum和右儿子maxl和的最大值。
4、该节点的maxr为右儿子的maxr与右儿子sum和左儿子maxr和的最大值。
5、该节点的sum为左右儿子的sum和。
查询时:
1、如果查询区间覆盖这一节点,将该节点信息返回。
2、如果只与一个儿子有交集,就返回在那个儿子中查找到的信息。
3、如果与两个儿子都有交集,就先分别计算出两个儿子的信息,然后按修改的方式将两个信息合并,然后返回。
4、最后返回的max值即为答案。
【代码实现】
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 program tyvj1427;
2 type tree=record
3 a,b,l,r,sum:longint;
4 maxl,maxr,max:longint;
5 end;
6 mm=record
7 maxl,maxr,max,sum:longint;
8 end;
9 var a:array[0..1000000]of tree;
10 i,j,m,n,k,x,y,l,r,tot,t:longint;
11 s:mm;
12 procedure make(l,r:longint);
13 var mid,now:longint;
14 begin
15 inc(tot);
16 a[tot].a:=l;
17 a[tot].b:=r;
18 now:=tot;
19 mid:=(l+r)shr 1;
20 if l<mid then
21 begin
22 a[now].l:=tot+1;
23 make(l,mid);
24 a[now].r:=tot+1;
25 make(mid,r);
26 end;
27 end;
28 function max(a,b:longint):longint;
29 begin
30 if a>b then exit(a)
31 else exit(b);
32 end;
33 procedure change(i,j:longint);
34 var mid:longint;
35 begin
36 if a[i].a=a[i].b-1 then
37 begin
38 a[i].sum:=x;
39 a[i].max:=x;
40 a[i].maxl:=x;
41 a[i].maxr:=x;
42 exit;
43 end;
44 mid:=(a[i].a+a[i].b)shr 1;
45 if j<=mid then change(a[i].l,j)
46 else change(a[i].r,j);
47 if (a[a[i].l].maxr<0)and(a[a[i].r].maxl<0) then a[i].max:=max(a[a[i].l].maxr,a[a[i].r].maxl)
48 else a[i].max:=max(a[a[i].l].maxr,0)+max(a[a[i].r].maxl,0);
49 a[i].max:=max(a[i].max,max(a[a[i].l].max,a[a[i].r].max));
50 a[i].maxl:=max(a[a[i].l].maxl,a[a[i].l].sum+a[a[i].r].maxl);
51 a[i].maxr:=max(a[a[i].r].maxr,a[a[i].r].sum+a[a[i].l].maxr);
52 a[i].sum:=a[a[i].l].sum+a[a[i].r].sum;
53 end;
54 function get(i,l,r:longint):mm;
55 var mid:longint;
56 now,s1,s2:mm;
57 v1,v2:boolean;
58 begin
59 v1:=false;v2:=false;
60 if (l<=a[i].a)and(a[i].b<=r) then
61 begin
62 now.maxl:=a[i].maxl;
63 now.maxr:=a[i].maxr;
64 now.max:=a[i].max;
65 now.sum:=a[i].sum;
66 exit(now);
67 end;
68 mid:=(a[i].a+a[i].b)shr 1;
69 if l<mid then
70 begin
71 s1:=get(a[i].l,l,r);
72 v1:=true;
73 end;
74 if mid<r then
75 begin
76 s2:=get(a[i].r,l,r);
77 v2:=true;
78 end;
79 if v1 and v2 then
80 begin
81 if (s1.maxr<0)and(s2.maxl<0) then now.max:=max(s1.maxr,s2.maxl)
82 else now.max:=max(s1.maxr,0)+max(s2.maxl,0);
83 now.max:=max(now.max,max(s1.max,s2.max));
84 now.maxl:=max(s1.maxl,s1.sum+s2.maxl);
85 now.maxr:=max(s2.maxr,s2.sum+s1.maxr);
86 now.sum:=s2.sum+s1.sum;
87 exit(now);
88 end
89 else if v1 then exit(s1)
90 else exit(s2);
91 end;
92 begin
93 readln(n,m);
94 make(0,n);
95 for i:=1 to n do
96 begin
97 read(x);
98 change(1,i);
99 end;
100 for i:=1 to m do
101 begin
102 readln(k,y,x);
103 if k=1 then
104 begin
105 if y>x then
106 begin
107 t:=y;
108 y:=x;
109 x:=t;
110 end;
111 if (y<=0)or(x>n) then continue;
112 s:=get(1,y-1,x);
113 writeln(s.max);
114 end
115 else if (y>=1)and(y<=n) then change(1,y);
116 end;
117 end.