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

本文介绍了一种求解区间最大子段和问题的有效算法,通过构建树状结构存储区间的关键信息,包括总和、最大子段和、最大前缀和及最大后缀和,并实现快速查询。

区间最大子段和

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

Input
The first line of the input file contains the integer NNN.
In the second line, NNN numbers follow.
The third line contains the integer MMM.
M lines follow, where line iii contains 222 numbers xix_ixi and yiy_iyi.

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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值