Evanyou Blog 彩带

P4513 小白逛公园

题目背景

小新经常陪小白去公园玩,也就是所谓的遛狗啦…

题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着 nnn 个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

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

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

输入输出格式

输入格式:

第一行,两个整数 NNN 和 MMM ,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来 NNN 行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来 MMM 行,每行三个整数。第一个整数 KKK , 111 或 222 。

  • K=1K=1K=1 表示,小新要带小白出去玩,接下来的两个整数 aaa 和 bbb 给出了选择公园的范围( 1≤a,b≤N1≤a,b≤N1a,bN );
  • K=2K=2K=2 表示,小白改变了对某个公园的打分,接下来的两个整数 ppp 和 sss ,表示小白对第 ppp 个公园的打分变成了 sss ( 1≤p≤N1≤p≤N1pN )。
    其中, 1≤N≤5000001≤N≤500 0001N500000 , 1≤M≤1000001≤M≤100 0001M100000 ,所有打分都是绝对值不超过 100010001000 的整数。
输出格式:

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

输入输出样例

输入样例#1: 
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
输出样例#1: 
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\n",query(x,y,1,n,1).all);}
        else {x=gi(),c=gi(),update(x,c,1,n,1);}
    }
    return 0;
}

 

posted @ 2018-05-22 21:47  five20  阅读(326)  评论(0编辑  收藏  举报
Live2D