1. 程式人生 > >GSS3 - Can you answer these queries III

GSS3 - Can you answer these queries III

#define RM () lse eset gin ++ hup tps

題意翻譯

nnn 個數, qqq 次操作

操作0 x yAxA_xAx? 修改為 yyy

操作1 l r詢問區間 [l,r][l, r][l,r] 的最大子段和

感謝 @Edgration 提供的翻譯

題目描述

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

輸入輸出格式

輸入格式:

The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

輸出格式:

For each query, print an integer as the problem required.

輸入輸出樣例

輸入樣例#1:
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3
輸出樣例#1:
6
4
-3


提交地址 : luogu SP1716
spoj;

分析:
線段樹水題


用線段樹維護四個值 : 這一區間的最大子段和, 這一區間的從最左端開始的最大子段和, 從右端開始的最大子段和,還有這一段的和;
怎麽維護?
	t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
	t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum);
	t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum);
	t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat));

就解釋一個:你左端開始的最大子段和一定是你左二子的左端點開始的最大子段和, 還有左二子全選加上右兒子的左端開始的最大子段和;

其他的都大同小異;

一樣的按照普通線段樹寫;

主要講講查詢操作;

因為我們要找一個連續的序列,而不是每個dat取max;

所以我們要維護一個前綴和qzh;

因為我們維護的是前綴和, 所以每次可以用 qzh+t[o].lsum 和 t[o].dat 取max來更新ans;

然後我們再改變qzh的值 在 qzh + t[o].sum 和 t[o].rsum中取max;

代碼奉上:

//zZhBr
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long

inline int read()
{
    int res=0;bool flag=0;char ch=getchar();
    while(!isdigit(ch)){if(ch==-)flag=1;ch=getchar();};
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-0);ch=getchar();}
    return flag?-res:res;
}

const int N = 50005;

int n, a[N], m;
int ans, qzh;

struct Segment
{
    int ls, rs;
    int l, r;
    int sum;
    int lsum, rsum;
    int dat;
}t[N<<1];
int cnt = 1;
int root;
#define ls(x) t[x].ls
#define rs(x) t[x].rs

inline void pushup(int o)
{
    t[o].l = t[ls(o)].l, t[o].r = t[rs(o)].r;
    t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
    t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum);
    t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum);
    t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat));
}

inline void build(int l, int r, int o)
{
    if (l == r)
    {
        t[o].sum = a[l];
        t[o].lsum = a[l];
        t[o].rsum = a[l];
        t[o].dat = a[l];
        t[o].l = t[o].r = l;
        return;
    }
    
    int mid = l + r >> 1;
    t[o].ls = cnt++;
    t[o].rs = cnt++;
    build(l, mid, ls(o));
    build(mid + 1, r, rs(o));
    pushup(o);
}

inline void change(int o, int x, int v)
{
    if (t[o].l == t[o].r)
    {
        t[o].sum = v;
        t[o].dat = v;
        t[o].lsum = t[o].rsum = v;
        return;
    }
    
    int mid = t[o].l + t[o].r >> 1;
    
    if (x <= mid) change(ls(o), x, v);
    else change(rs(o), x, v);
    pushup(o);
}

inline void query(int o, int li, int ri)
{    
    if (li <= t[o].l and ri >= t[o].r) 
    {
        ans = max(ans, max(qzh + t[o].lsum, t[o].dat));
        qzh = max(qzh + t[o].sum, t[o].rsum);
        return;
    }
    int res = 0;
    int mid = t[o].r + t[o].l >> 1;
    if (li <= mid) query(ls(o), li, ri);
    if (ri > mid) query(rs(o), li, ri);    
}

signed main()
{
    n = read();
    for (register int i = 1 ; i <= n ; i ++) a[i] = read();
    m = read();
    root = cnt++;
    build(1, n, root);
    
    while (m--)
    {
        int opt = read();
        int x = read(), y = read();
        
        if (opt == 0)
        {
            change(root, x, y);
        }
        else 
        {
            ans = -1e9, qzh = -1e9;
            query(root, x, y);
            printf("%lld\n", ans);
        }
    }
    
    return 0;
    
}

GSS3 - Can you answer these queries III