bzoj1756: Vijos1083 小白逛公园

传送门
用线段树维护区间最大前缀后缀,区间最优解和区间和。
合并时候xjb乱搞以下就可以了。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
using namespace std;
int a[N],n,m,fl,x,y;
struct node{int mx,lmx,rmx,sum;}t[N*4];
node merge(node a,node b){
    node tmp;
    tmp.lmx=max(a.lmx,a.sum+b.lmx);
    tmp.rmx=max(b.rmx,b.sum+a.rmx);
    tmp.mx=max(a.rmx+b.lmx,max(a.mx,b.mx));
    tmp.sum=a.sum+b.sum;
    return tmp;
}
void build(int k,int l,int r){
    if (l==r){
        t[k].mx=t[k].lmx=t[k].rmx=t[k].sum=a[l];
        return;
    }
    int mid=(l+r)/2;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    t[k]=merge(t[k*2],t[k*2+1]);
}
void change(int k,int l,int r,int x,int v){
    if (l==r){
        t[k].mx=t[k].lmx=t[k].rmx=t[k].sum=v;
        return;
    }
    int mid=(l+r)/2;
    if (x<=mid) change(k*2,l,mid,x,v);
    else change(k*2+1,mid+1,r,x,v);
    t[k]=merge(t[k*2],t[k*2+1]); 
}
node ask(int k,int l,int r,int x,int y){
    if (l==x&&r==y) return t[k];
    int mid=(l+r)/2;
    if (y<=mid) return ask(k*2,l,mid,x,y);
    if (x>mid) return ask(k*2+1,mid+1,r,x,y);
    return merge(ask(k*2,l,mid,x,mid),ask(k*2+1,mid+1,r,mid+1,y)); 
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    for (int i=1;i<=m;i++){
        scanf("%d%d%d",&fl,&x,&y);
        if (fl==1){
            if (x>y) swap(x,y);
            printf("%d\n",ask(1,1,n,x,y).mx);
        }
        else change(1,1,n,x,y);
    }
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页