VIJOS 1083 小白逛公园 线段树

【vijos1083】小白逛公园

描述
小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a、b两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
输入格式
第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来N行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,小新要带小白出去玩,接下来的两个整数a和b给出了选择公园的范围(1≤a,b≤N, a可以大于b!);K=2表示,小白改变了对某个公园的打分,接下来的两个整数p和s,表示小白对第p个公园的打分变成了s(1≤p≤N)。
其中,1≤N≤500 000,1≤M≤100 000,所有打分都是绝对值不超过1000的整数。
输出格式
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

分析:裸的线段树维护区间和,可以拿来做模板,注意tr有4个标记,ml表示从左端开始的最大和,mr是从右端开始的最大字段和,mx是区间中的最大连续字段和,sum是区间和,然后不难看出这样维护:
sum[h] = sum[h << 1] + sum[h << 1|1];
ml[h]= max(ml[h<<1],sum[h<<1]+ml[h<<1|1]);
mr[h]=max(mr[h<<1|1],sum[<<1|1]+mr[h<<1]; mx[h]=max(max(mx[h<<1],mx[h<<1|1]),ml[h<<1|1]+mr[h<<1]);

# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
# include <queue>
# include <cmath>
# include <vector>
using namespace std;
int read(){
    register int f=1,i=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
    return f*i;
}
const int N=2000000+10;
struct node{
    int ml,mr,mx,sum;
    node(){};
    node(int ml,int mr,int mx,int sum) : ml(ml),mr(mr),mx(mx),sum(sum){}
}tr[N];
int n,m,x,y,z,k,a[N];
struct seg{
    inline void change(int k){
        tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
        tr[k].ml=max(tr[k<<1].ml,tr[k<<1].sum+tr[k<<1|1].ml);
        tr[k].mr=max(tr[k<<1|1].mr,tr[k<<1|1].sum+tr[k<<1].mr);
        tr[k].mx=max(max(tr[k<<1].mx,tr[k<<1|1].mx),tr[k<<1].mr+tr[k<<1|1].ml);
    }
    inline void build(int k,int l,int r){
        if(l==r){
            tr[k].sum=tr[k].mx=tr[k].ml=tr[k].mr=a[l];
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid),build(k<<1|1,mid+1,r);
        change(k);
    }
    inline void update(int k,int l,int r,int pos,int x){
        if(l==r){
            tr[k].sum=tr[k].mx=tr[k].ml=tr[k].mr=x;
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid) update(k<<1,l,mid,pos,x);
        if(pos>mid) update(k<<1|1,mid+1,r,pos,x);
        change(k);
    }
    node query(int k,int l,int r,int s,int t){
        if(s==l&&r==t){
            node tmp=node(tr[k].ml,tr[k].mr,tr[k].mx,tr[k].sum);
            return tmp;
        }
        int mid=l+r>>1;
        if(t<=mid) return query(k<<1,l,mid,s,t);
        else if(s>mid) return query(k<<1|1,mid+1,r,s,t);
        node a,b,tmp;
        a=query(k<<1,l,mid,s,mid);
        b=query(k<<1|1,mid+1,r,mid+1,t);
        tmp.mx=max(max(a.mx,b.mx),a.mr+b.ml);
        tmp.ml=max(a.ml,a.sum+b.ml);
        tmp.mr=max(b.mr,b.sum+a.mr);
        return tmp;
    }
}Seg;
int main(){
    freopen("lx.in","r",stdin);
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    Seg.build(1,1,n);
    for(int i=1;i<=m;++i){
        k=read();
        if(k==1){
            x=read(),y=read();
            if(x > y)swap(x,y);
            printf("%d\n",Seg.query(1,1,n,x,y).mx);
        }else{
            x=read(),y=read();
            Seg.update(1,1,n,x,y);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值