[線段樹點修改]動態最大連續和(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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章