题目背景
小新经常陪小白去公园玩,也就是所谓的遛狗啦…
题目描述
在小新家附近有一条“公园路”,路的一边从南到北依次排着 nnn 个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第 aaa 个和第 bbb 个公园之间(包括 aaa 、 bbb 两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
输入输出格式
输入格式:第一行,两个整数 NNN 和 MMM ,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来 NNN 行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来 MMM 行,每行三个整数。第一个整数 KKK , 111 或 222 。
- K=1K=1K=1 表示,小新要带小白出去玩,接下来的两个整数 aaa 和 bbb 给出了选择公园的范围( 1≤a,b≤N1≤a,b≤N1≤a,b≤N );
- K=2K=2K=2 表示,小白改变了对某个公园的打分,接下来的两个整数 ppp 和 sss ,表示小白对第 ppp 个公园的打分变成了 sss ( 1≤p≤N1≤p≤N1≤p≤N )。
其中, 1≤N≤5000001≤N≤500 0001≤N≤500000 , 1≤M≤1000001≤M≤100 0001≤M≤100000 ,所有打分都是绝对值不超过 100010001000 的整数。
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
输入输出样例
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
2
-1
Solution:
本题实在是鬼~~(善用结构体啊!又是调半天不出来的题~)
经典的带修改的区间最大连续子段和问题,典型的线段树嘛~!
写了一个数组版线段树,不知道查询怎么去维护了,最后还是借鉴别人的代码,学了一波结构体写线段树的风格。
建一棵线段树维护一下信息:$lmx$(与左边界相连的最大连续子段和),$rmx$(与右端点相连的最大连续子段和),$all$(整个区间的最大连续子段和),$sum$(整个区间的和)。
那么还是正常的单点修改,只不过每次$pushup$自下而上维护节点$rt$的信息时,需要这些操作:
1、当左儿子$ls$的$rmx$和右儿子$rs$的$lmx$均为$<0$时,整个区间的最大连续子段和$rt.all$直接取$Max(rs.lmx,ls.rmx)$。否则$rt.all$加上左右儿子中不为负值的$ls.rmx,rs.lmx$,然后$rt.all$再与单独的$ls.all$和$rs.all$中取最大值。
2、当前节点$rt$的与左端点相连的最大连续子段和,在左儿子$ls.lmx$和右儿子$rs.lmx+ls.sum$中取最大值。
3、同理当前节点$rt$的与右端点相连的最大连续子段和,在右儿子$rs.rmx$和左儿子$ls.rmx+rs.sum$中取最大值。
4、不要忘了维护整个区间的和,$rt.sum=ls.sum+rs.sum$。
(注意$pushup$函数的变量为结构体,左右儿子定义为$const node &ls$和$const node &rs$,因为查询时不能确定一段区间的最大连续子段和,所以需要想$pushup$函数一样更新一下整个区间的信息,定义变量为结构体能方便后面查询维护区间最大子段和,加$const$是因为$ls,rs$本身也是个变量)
再讲下写的吐血的查询(注意坑点,区间可能$l>r$),整个递归过程参考了神犇的代码(这个结构体的递归写的太美妙了~!),首先将一段区间分为多个小区间,当区间包含时直接返回当前区间,然后每次递归向上用$pushup$维护整段查询的区间,引入一个结构体变量$a$记录整段区间的值。最后输出的是返回结构体变量的成员$all$(即该区间的最大连续子段和)。
(写完此题,又“深度”理解了一波线段树~唉~太菜了`~)
代码:
#include<bits/stdc++.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define il inline #define ll long long #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int N=500005; int n,m; struct node{ ll sum,lmx,rmx,all; }t[N<<2]; il int gi(){ int a=0;char x=getchar();bool f=0; while((x<'0'||x>'9')&&x!='-')x=getchar(); if(x=='-')x=getchar(),f=1; while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar(); return f?-a:a; } il void pushup(node &rt,const node &ls,const node &rs){ if(ls.rmx<0&&rs.lmx<0)rt.all=Max(ls.rmx,rs.lmx); else { rt.all=0; if(ls.rmx>0)rt.all+=ls.rmx; if(rs.lmx>0)rt.all+=rs.lmx; } rt.all=Max(rt.all,Max(ls.all,rs.all)); rt.lmx=Max(ls.lmx,ls.sum+rs.lmx); rt.rmx=Max(rs.rmx,rs.sum+ls.rmx); rt.sum=ls.sum+rs.sum; } il void build(int l,int r,int rt){ if(l==r){t[rt].all=t[rt].sum=t[rt].lmx=t[rt].rmx=gi();return;} int m=l+r>>1; build(lson),build(rson); pushup(t[rt],t[rt<<1],t[rt<<1|1]); } il void update(int L,int c,int l,int r,int rt){ if(l==r){t[rt].all=t[rt].sum=t[rt].lmx=t[rt].rmx=c;return;} int m=l+r>>1; if(L<=m)update(L,c,lson); else update(L,c,rson); pushup(t[rt],t[rt<<1],t[rt<<1|1]); } il node query(int L,int R,int l,int r,int rt){ if(L<=l&&R>=r)return t[rt]; int m=l+r>>1; if(L<=m&&R>m){node a;pushup(a,query(L,R,lson),query(L,R,rson));return a;} else if(L<=m)return query(L,R,lson); return query(L,R,rson); } int main(){ n=gi(),m=gi(); build(1,n,1); int k,x,y,c; while(m--){ k=gi(); if(k==1){x=gi(),y=gi();if(x>y)swap(x,y);printf("%lld ",query(x,y,1,n,1).all);} else {x=gi(),c=gi(),update(x,c,1,n,1);} } return 0; }