TYVJ1427 小白逛公园

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值即为答案。

 【代码实现】

Code
  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.

 

 

转载于:https://www.cnblogs.com/whitecloth/archive/2012/03/22/2410925.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值