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 }