1. 程式人生 > >CHOJ 4301【線段樹+區間最大子段和】

CHOJ 4301【線段樹+區間最大子段和】

描述

給定長度為N的數列A,以及M條指令 (N≤500000, M≤100000),每條指令可能是以下兩種之一: “2 x y”,把 A[x] 改成 y。 “1 x y”,查詢區間 [x,y] 中的最大連續子段和,即 max(x≤l≤r≤y)⁡ { ∑(i=l~r) A[i] }。 對於每個詢問,輸出一個整數表示答案。

輸入格式

第一行兩個整數N,M

第二行N個整數Ai

接下來M行每行3個整數k,x,y,k=1表示查詢(此時如果x>y,請交換x,y),k=2表示修改

輸出格式

對於每個詢問輸出一個整數表示答案。

樣例輸入

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2

樣例輸出

2
-1

資料範圍與約定

  • 對於100%的資料: N≤500000, M≤100000, |Ai|<=1000

題解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF -0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 500010;
int n, m;
int a[maxn];
struct SegmentTree{
    int l, r;
    int dat, sum, lmax, rmax;
}t[maxn<<2];
void init(SegmentTree &tree, int x){
    tree.dat=tree.lmax=tree.rmax=tree.sum=x;
}
void push_up(int p){
    t[p].sum = t[2*p].sum + t[2*p+1].sum;
    t[p].lmax = max(t[2*p].lmax, t[2*p].sum+t[2*p+1].lmax);
    t[p].rmax = max(t[2*p+1].rmax, t[2*p+1].sum+t[2*p].rmax);
    t[p].dat = max(t[2*p].dat, max(t[2*p+1].dat, t[2*p].rmax+t[2*p+1].lmax));
}
void build(int p, int l, int r){
    t[p].l = l, t[p].r = r;
    if(l == r){
        init(t[p], a[l]);
        return;
    }
    int mid = (l+r)/2;
    build(2*p, l, mid);
    build(2*p+1, mid+1, r);
    push_up(p);
}
void change(int p, int x, int val){
    if(t[p].l == t[p].r){
        init(t[p], val);
        return ;
    }
    int mid = (t[p].l+t[p].r)/2;
    if(x <= mid) change(2*p, x, val);
    else change(2*p+1, x, val);
    push_up(p);
}
SegmentTree ask(int p, int l, int r){
    if(l <= t[p].l && r >= t[p].r){
        return t[p];
    }
    int mid = (t[p].l+t[p].r)/2;
    SegmentTree a, b, c;
    init(a, INF), init(b, INF);
    c.sum = 0;
    if(l <= mid) {
        a = ask(2*p, l, r);
        c.sum += a.sum;
    }
    if(r > mid) {
        b = ask(2*p+1, l, r);
        c.sum += b.sum;
    }
    c.dat = max(max(a.dat, b.dat), a.rmax+b.lmax);
    c.lmax = max(a.lmax, b.lmax+a.sum);
    c.rmax = max(b.rmax, a.rmax+b.sum);
    return c;
}
int main()
{
    int k, x, y;
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    build(1,1,n);
    while(m--){
        cin >> k >> x >> y;
        if(k == 1){
            if(x > y) swap(x, y);
            printf("%d\n", ask(1,x,y).dat);
        }else change(1,x,y);
    }
    return 0;
}