洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)
P4513 小白逛公园
题目背景
小新经常陪小白去公园玩,也就是所谓的遛狗啦…
题目描述
在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
输入输出格式
输入格式:
第一行,两个整数NN和MM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来MM行,每行三个整数。第一个整数KK,11或22。
- K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1≤a,b≤N)。测试数据可能会出现a>ba>b的情况,需要进行交换;
- K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1≤p≤N)。
其中,1≤N≤500 0001≤N≤500000,1≤M≤100 0001≤M≤100000,所有打分都是绝对值不超过10001000的整数。
输出格式:
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
输入输出样例
区间最大子段和,正常的区间不变的可以分治或者dp啥的,线段树的就维护最大前缀和,最大后缀和,之类的。
具体的代码写了注释。。。
代码:
1 //线段树-分治+区间合并 2 //区间最大子段和有三种情况: 3 //1.左子树最大子段和 4 //2.右子树最大子段和 5 //3.左子树的最大后缀和+右子树的最大前缀和 6 7 //思路特别简单,但是写自己顺手的模板改的时间有点久,最后选择了这种方式,其他int返回值的函数有代码重复的操作 8 9 #include<bits/stdc++.h> 10 using namespace std; 11 typedef long long ll; 12 const int maxn=5e5+10; 13 14 #define lson l,m,rt<<1 15 #define rson m+1,r,rt<<1|1 16 17 struct Tree{ 18 int pre,suf,sub,val;//pre为当前区间最大前缀和,suf为当前区间最大后缀和,sub为当前区间最大子段和,val为当前区间的和 19 }tree[maxn<<2]; 20 21 Tree pushup(Tree l,Tree r) 22 { 23 Tree rt; 24 rt.pre=max(l.pre,l.val+r.pre);//当前区间的最大前缀和:左子树的最大前缀和 or 左子树的和+右子树的最大前缀和 25 rt.suf=max(r.suf,r.val+l.suf);//当前区间的最大后缀和:右子树的最大后缀和 or 右子树的和+左子树的最大后缀和 26 rt.sub=max(max(l.sub,r.sub),l.suf+r.pre);//当前区间的最大子段和:左子树的最大子段和 or 右子树的最大子段和 or 左子树的最大后缀和+右子树的最大前缀和 27 rt.val=l.val+r.val;//当前区间的和:左子树的和+右子树的和 28 return rt; 29 } 30 31 void build(int l,int r,int rt) 32 { 33 if(l==r){ 34 scanf("%d",&tree[rt].val); 35 tree[rt].pre=tree[rt].suf=tree[rt].sub=tree[rt].val; 36 return ; 37 } 38 39 int m=(l+r)>>1; 40 build(lson); 41 build(rson); 42 tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]); 43 } 44 45 void update(int pos,int c,int l,int r,int rt) 46 { 47 if(l==r){ 48 tree[rt].pre=tree[rt].suf=tree[rt].sub=tree[rt].val=c; 49 return ; 50 } 51 52 int m=(l+r)>>1; 53 if(pos<=m) update(pos,c,lson); 54 if(pos> m) update(pos,c,rson); 55 tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]); 56 } 57 58 Tree query(int L,int R,int l,int r,int rt) 59 { 60 if(L<=l&&r<=R){ 61 return tree[rt]; 62 } 63 64 int m=(l+r)>>1; 65 Tree ret,lret,rret; 66 int flag1=0,flag2=0; 67 if(L<=m) {lret=query(L,R,lson);flag1=1;} 68 if(R> m) {rret=query(L,R,rson);flag2=1;} 69 70 if(flag1&&flag2) ret=pushup(lret,rret);//合并 71 else if(flag1) ret=lret; 72 else if(flag2) ret=rret; 73 return ret; 74 } 75 76 int main() 77 { 78 int n,m; 79 scanf("%d%d",&n,&m); 80 build(1,n,1); 81 for(int i=1;i<=m;i++){ 82 int op; 83 scanf("%d",&op); 84 if(op==1){ 85 int l,r; 86 scanf("%d%d",&l,&r); 87 if(l>r) swap(l,r); 88 Tree ans=query(l,r,1,n,1); 89 printf("%d\n",ans.sub); 90 } 91 else{ 92 int p,s; 93 scanf("%d%d",&p,&s); 94 update(p,s,1,n,1); 95 } 96 } 97 return 0; 98 }