spoj GSS1.区间最大子段和(线段树)

区间最大子段和

You are given a sequence \(A[1], A[2], ..., A[N]. ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000)\). A query is defined as follows:
\(Query(x,y) = Max (a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y)\).
Given M queries, your program must output the results of these queries.

Input
The first line of the input file contains the integer \(N\).
In the second line, \(N\) numbers follow.
The third line contains the integer \(M\).
M lines follow, where line \(i\) contains \(2\) numbers \(x_i\) and \(y_i\).

Output
Your program should output the results of the M queries, one query per line.

Example
Input:

3
-1 2 3
1
1 2

Output:

2

Solution

对于每一个每个区间,保存一个Node,记录这个区间的sum(总和),maxsum(最大子段和),lmax(最大前缀和),rmax(最大后缀和),有了这四个标记,就可以随意转移,为所欲为了。。。
这里我们把核心代码拉出来讲一讲

ans.sum = lo.sum + ro.sum;//sum直接相加
ans.maxsum = max(max(lo.maxsum, ro.maxsum), lo.rmax + ro.lmax);//左右两半的最大子段和,合并起来的最大子段和
ans.lmax = max(lo.lmax, lo.sum + ro.lmax);//左边的最大前缀和,左边整段+右边最大前缀
ans.rmax = max(ro.rmax, ro.sum + lo.rmax);//右边的最大后缀和,右边整段+左边最大后缀

Code

#include <cstdio>
#include <algorithm>
#define N 50010

using namespace std;

struct Node{
    int sum, maxsum, lmax, rmax;
}tr[N << 2];
int a[N];

void build(int l, int r, int id) {
    if (l == r) {
        tr[id].sum = tr[id].maxsum = tr[id].lmax = tr[id].rmax = a[l];
        return;
    }
    int mid = (l + r) >> 1, ls = id << 1, rs = id << 1 | 1;
    build(l, mid, ls);
    build(mid + 1, r, rs);
    tr[id].sum = tr[ls].sum + tr[rs].sum;
    tr[id].maxsum = max(max(tr[ls].maxsum, tr[rs].maxsum), tr[ls].rmax + tr[rs].lmax);
    tr[id].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);
    tr[id].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
}

Node query(int l, int r, int ll, int rr, int id) {
    if (ll <= l && r <= rr) {
        return tr[id];
    }
    int mid = (l + r) >> 1, ls = id << 1, rs = id << 1 | 1;
    if (rr <= mid) return query(l, mid, ll, rr, ls);
    if (mid < ll) return query(mid + 1, r, ll, rr, rs);
    Node lo = query(l, mid, ll, rr, ls), ro = query(mid + 1, r, ll, rr, rs), ans;
    ans.sum = lo.sum + ro.sum;
    ans.maxsum = max(max(lo.maxsum, ro.maxsum), lo.rmax + ro.lmax);
    ans.lmax = max(lo.lmax, lo.sum + ro.lmax);
    ans.rmax = max(ro.rmax, ro.sum + lo.rmax);
    return ans;
}

int main() {
    int n, m;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    build(1, n, 1);
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        printf("%d\n", query(1, n, x, y, 1).maxsum);
    }
    return 0;
}
posted @ 2018-11-07 14:42  Fxkkks  阅读(352)  评论(0编辑  收藏  举报