最大字段和--GSS1 MUSHROOM ORZ

过于naive了= =作为一个知识点总结一下算了。主要就是合并。对于一个区间的最大字段和,可以分别事下面的两个区间的子段和,或者事左边的右边加右边的左边。然后搞一下 = =

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long ll;
const ll maxn = 3000100;

ll lson[maxn], rson[maxn], lm[maxn], rm[maxn], mans[maxn], sum[maxn];
ll ne = 0, root;

ll build(ll l, ll r) {
    ll now = ++ ne;
    if(l ^ r) {
        ll mid = (l + r) >> 1;
        lson[now] = build(l, mid);
        rson[now] = build(mid + 1, r);
    }
    return now;
}

void update(ll now) {
    if(lson[now]) {
        sum[now] = sum[lson[now]] + sum[rson[now]];
        lm[now] = max(lm[lson[now]], sum[lson[now]] + lm[rson[now]]);
        rm[now] = max(rm[rson[now]], sum[rson[now]] + rm[lson[now]]);
        mans[now] = max(max(mans[lson[now]], mans[rson[now]]), lm[rson[now]] + rm[lson[now]]);
    }
}

void insert(ll now, ll l, ll r, ll v, ll pos) {
    if(l == r) {
        sum[now] = lm[now] = rm[now] = mans[now] = v;
    }
    else {
        ll mid = (l + r) >> 1;
        if(pos <= mid) insert(lson[now], l, mid, v, pos);
        else insert(rson[now], mid + 1, r, v, pos);
        update(now);
    }
}

ll ask(ll now, ll l, ll r, ll ls, ll rs) {
    ll ret;
    if(l == ls && r == rs) ret = now;
    else {
        ll mid = (l + r) >> 1;
        if(rs <= mid) ret = ask(lson[now], l, mid ,ls, rs);
        else if(ls >= mid + 1) ret = ask(rson[now], mid + 1, r, ls, rs);
        else {
            ret = ++ ne;
            ll rl = ask(lson[now], l, mid, ls, mid);
            ll rr = ask(rson[now], mid + 1, r, mid + 1, rs);
            lson[ret] = rl, rson[ret] = rr;
            update(ret);
        }
    }
    return ret;
}

ll ll_get() {
    ll x = 0; char c = (char)getchar(); bool flag = 0;
    while(!isdigit(c) && c != '-') c = (char)getchar();
    if(c == '-') flag = 1;
    while(!isdigit(c)) c = (char)getchar();
    while(isdigit(c)) {
        x = x * 10 + (ll)(c - '0');
        c = (char)getchar();
    }
    if(flag) x = -x;
    return x;
}

ll n, m;

void sov() {
    n = ll_get(); root = build(1, n);
    for(ll i = 1; i <= n; ++ i) {
        ll a = ll_get();
        insert(root, 1, n, a, i);
    }
    m = ll_get();
    while(m --) {
        ll ls, rs; ls = ll_get(), rs = ll_get();
        ll ans = ask(root, 1, n, ls, rs);
        printf("%lld\n", mans[ans]);
    }
}

int main() {
    //freopen("test.in", "r", stdin);
    //freopen("b.out", "w", stdout);
    sov();
    return 0;
}

 

转载于:https://www.cnblogs.com/ianaesthetic/p/3988806.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值