luogu4513 小白逛公园

题目

Description
小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

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

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

Input
第一行,两个整数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的整数。

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

Sample Input
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
Sample Output
2
-1

分析

本题求的是指定区间的最大连续子段和,和单点修改

(方法略复杂,线段树与动规杂交,但空间较小)

part 1

用结构体维护每个二分区间的总和(to),从左边开始的最大连续子段和(le), 从右边开始的最大连续子段和(ri) 及该区间的最大连续子段和(v)

part 2

全局量maxn:存当前的最大和(只包含横跨两个或两个以上区间的情况)

maxa:存以当前区间结尾的最大和

依据:是cx函数的深搜顺序是从左到右

part 3

cx函数:返回值是各个子区间的各自的最大和中的最大值,最后输出的是它与maxn 比较的结果 

part 4

坑点:a可能大于b

 代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,maxa,maxn;
 4 struct ee{
 5     int le,ri,v,to;
 6 }a[2000004];
 7 
 8 void init(){
 9     freopen("1.txt","r",stdin);
10 }
11 
12 void js(int l,int r,int z){//建树 
13     if(l==r){
14         scanf("%d",&a[z].v);
15         a[z].le=a[z].v;
16         a[z].ri=a[z].v;
17         a[z].to=a[z].v;
18         return;                                            
19     }
20     int mid=(l+r)>>1;
21     int zz=z<<1;
22     int y=zz|1;
23     js(l,mid,zz);
24     js(mid+1,r,y);
25     a[z].v=max(a[zz].v,max(a[zz].ri+a[y].le,a[y].v));
26     a[z].le=max(a[zz].le,a[zz].to+a[y].le);
27     a[z].ri=max(a[y].ri,a[y].to+a[zz].ri);
28     a[z].to=a[zz].to+a[y].to;
29 }
30 
31 int cx(int l,int r,int x,int y,int z){
32     if(x<=l&&y>=r) {
33         if(x==l){
34                 maxa=a[z].ri;
35                 maxn=maxa;
36         }
37         else{
38             if(y!=r){
39                 maxn=max(max(maxn,a[z].ri),max(maxa+a[z].to,maxa+a[z].le));
40                 maxa=max(maxa+a[z].to,a[z].ri);//这里是保证以当前区间结尾的子段和最大 
41             }
42             else{
43                 maxa=maxa+a[z].le;
44                 if(maxa>maxn) maxn=maxa;
45             }//动规 
46         }
47         return a[z].v;
48     }
49     int mid=(l+r)>>1;
50     int zz=z<<1;
51     int maxans=-1<<31;
52     if(x<=mid) maxans=cx(l,mid,x,y,zz);
53     if(y>mid) maxans=max(maxans,cx(mid+1,r,x,y,zz|1));
54     return maxans;
55 }
56 
57 void xg(int l,int r,int x,int y,int z) {//修改时和建树很像
58     if(l==r){
59         a[z].v=y;
60         a[z].le=a[z].v;
61         a[z].ri=a[z].v;
62         a[z].to=a[z].v;
63         return;
64     }
65     int mid=(l+r)>>1;
66     int zz=z<<1;
67     int yy=zz|1;
68     if(x<=mid) xg(l,mid,x,y,zz);
69     else xg(mid+1,r,x,y,yy);
70     a[z].v=max(a[zz].v,max(a[zz].ri+a[yy].le,a[yy].v));
71     a[z].le=max(a[zz].le,a[zz].to+a[yy].le);
72     a[z].ri=max(a[yy].ri,a[yy].to+a[zz].ri);
73     a[z].to=a[zz].to+a[yy].to;//维护
74 }
75 
76 void readdata(){
77     scanf("%d%d",&n,&m);
78     js(1,n,1);
79     for(int i=1;i<=m;i++){
80         int k,a,b;
81         scanf("%d%d%d",&k,&a,&b);
82         if(k==1) {
83             int c;
84             if(a>b) c=cx(1,n,b,a,1);
85             else c=cx(1,n,a,b,1);
86             printf("%d\n",max(c,maxn));
87         }
88         else xg(1,n,a,b,1);
89     }
90 }
91 
92 int main(){
93     //init();
94     readdata();
95     return 0;
96 }
View Code

 

posted @ 2019-01-25 09:13  Mandy_H_Y  阅读(423)  评论(3编辑  收藏  举报