[线段树点修改]动态最大连续和(Ray,Pass me the Dishes, LA 3938)

[线段树点修改]动态最大连续和(Ray,Pass me the Dishes, LA 3938)

“Ray, Pass me the dishes!”
After doing Ray a great favor to collect sticks for Ray, Poor Neal becomes very hungry. In return for Neal’s help, Ray makes a great dinner for Neal. When it is time for dinner, Ray arranges all the dishes he makes in a single line (actually this line is very long … …
Every dish has its own value represented by an integer whose absolute value is less than 1,000,000,000. Before having dinner, Neal is wondering about the total value of the dishes he will eat. So he raises many questions about the values of dishes he would have.
For each question Neal asks, he will first write down an interval [a, b] a, a + 1,…, b a b
Input
The input file contains multiple test cases. For each test case, there are two integers n m (n, m < 500000) n m
Then n m a b
Output
For each test case, output m
Sample Input
3 1
1 2 3
1 1
Sample Output
Case 1:
1 1

题意: 给出一个长度为n的序列, 再给出m个询问, 每个询问是在序列[a, b]之间的最大连续和. 要你计算出这个
这个区间内最大连续和的区间[x, y]; (a<=x<=y<=b);

思路:1、构造线段树,其中每个结点维护3个值,最大连续和max_sub,最大前缀和max_prefix,最大后缀和max_suffix。
具体来说,max_sub(a,b)是满足a <=x<=y<=b且Dx+Dx+1+…+Dy最大的二元组(x, y);
max_prefix(a, b)是满足a <= x<=b且Da+Da+1+…+Dx最大的整数x;
max_suffix(a, b)是满足a <= x<=b且Dx+Dx+1+…+Db最大的整数x;
比如n=64,询问为(20,50),则线段[20,50]在线段树的根结点处被分成了两条线段[20,32]和[33,50]。则max_sub(20, 50)的起点和终点有3种情况。
情况一:起点和终点都在[20,32]中,则max_sub(20, 50)=max_sub(20, 32)。
情况二:起点和终点都在[33,50]中,则max_sub(20, 50)=max_sub(33, 50)。
情况三:起点在[20,32]中,终点在[33,50]中,则max_sub(20, 50)=(max_suffix(20, 32),max_prefix(33,50))。
类似地max_suffix和max_prefix也可以这样递推,建树的时间复杂度为o(n),单组查询的时间复杂度为o(logn)。

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 500000;
typedef long long LL;
#define LL(x) x<<1
#define RR(x) x<<1|1
struct tree {
    int left, right, mid;
    LL max_pre, max_suf, max_sub, sum;
    int sub1, subr, prer, suf1;
}node[maxn<<2];
LL a[maxn];
void BuildTree(int L, int R, int rt) {
    node[rt].mid = (L+R)/2;
    node[rt].left = L;
    node[rt].right = R;
    if (L == R) {
        node[rt].max_pre = node[rt].max_sub = node[rt].max_suf = node[rt].sum = a[L];
        node[rt].sub1 = node[rt].subr = node[rt].prer = node[rt].suf1 = L;
        return;
    }
    int lx = LL(rt);
    int rx = RR(rt);
    BuildTree(L, node[rt].mid, lx);
    BuildTree(node[rt].mid+1, R, rx);
    node[rt].sum = node[lx].sum + node[rx].sum;
    if (node[lx].max_pre >= node[lx].sum+node[rx].max_pre) {
        node[rt].max_pre = node[lx].max_pre;
        node[rt].prer = node[lx].prer;
    } else {
        node[rt].max_pre = node[rx].max_pre + node[lx].sum;
        node[rt].prer = node[rx].prer;
    }
    if (node[rx].max_suf > node[rx].sum+node[lx].max_suf) {
        node[rt].max_suf = node[rx].max_suf;
        node[rt].suf1 = node[rx].suf1;
    } else {
        node[rt].max_suf = node[lx].max_suf + node[rx].sum;
        node[rt].suf1 = node[lx].suf1;
    }
    if (node[lx].max_sub >= max(node[rx].max_sub, node[rx].max_pre + node[lx].max_suf)) {
        node[rt].max_sub = node[lx].max_sub;
        node[rt].sub1 = node[lx].sub1;
        node[rt].subr = node[lx].subr;
    } else if (node[rx].max_sub <= node[rx].max_pre + node[lx].max_suf) {
        node[rt].max_sub = node[rx].max_pre + node[lx].max_suf;
        node[rt].sub1 = node[lx].suf1;
        node[rt].subr = node[rx].prer;
    } else {
        node[rt].max_sub = node[rx].max_sub;
        node[rt].sub1 = node[rx].sub1;
        node[rt].subr = node[rx].subr;
    }
    return;
}
tree Query(int L, int R, int rt) {
    if (L == node[rt].left && R == node[rt].right) {
        return node[rt];
    } else if (R <= node[rt].mid) {
        return Query(L, R, rt<<1);
    } else if (L > node[rt].mid){
        return Query(L, R, (rt<<1)+1);
    } else {
        tree a1 = Query(L, node[rt].mid, rt<<1);
        tree a2 = Query(node[rt].mid+1, R, (rt<<1)+1);
        tree ans;
        ans.left = L;
        ans.right = R;
        ans.mid = (L+R)/2;
        if (a1.max_pre >= a1.sum+a2.max_pre) {
            ans.max_pre = a1.max_pre;
            ans.prer = a1.prer;
        } else {
            ans.max_pre = a1.sum + a2.max_pre;
            ans.prer = a2.prer;
        }
        if (a1.max_suf + a2.sum >= a2.max_suf) {
            ans.max_suf = a1.max_suf + a2.sum;
            ans.suf1 = a1.suf1;
        } else {
            ans.max_suf = a2.max_suf;
            ans.suf1 = a2.suf1;
        }
        if (a1.max_sub >= max(a2.max_sub, a2.max_pre + a1.max_suf)) {
            ans.max_sub = a1.max_sub;
            ans.sub1 = a1.sub1;
            ans.subr = a1.subr;
        } else if (a2.max_sub <= a2.max_pre + a1.max_suf) {
            ans.max_sub = a2.max_pre + a1.max_suf;
            ans.sub1 = a1.suf1;
            ans.subr = a2.prer;
        } else {
            ans.max_sub = a2.max_sub;
            ans.sub1 = a2.sub1;
            ans.subr = a2.subr;
        }
        return ans;
    }
}
int main() {
    int n, m, x, y;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    BuildTree(1, n, 1);
    while (m--) {
        scanf("%d%d", &x, &y);
        tree ans = Query(x, y, 1);
        printf("%d %d\n", ans.sub1, ans.subr);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值