UVA live 3938 - "Ray, Pass me the dishes!"(线段树)

题目链接:点击打开链接

该题需要深刻理解线段树的特点:任意一个父结点所表示的区间都是两个儿子区间的并, 且儿子区间的交为空集。

那么我们可以采用分治的思想: 一段区间的最大连续和要么来自左半边, 要么来自右半边, 或者一半在左一半在右。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll INF = (ll)1e15;
const int maxn = 300000+10;
int T,n,A,B,m;
struct node {
    ll v;
    int l, r;
    node(ll v=0, int l=0, int r=0): v(v), l(l), r(r) {}
}maxv[maxn<<2], pre[maxn<<2], last[maxn<<2], sum[maxn<<2];
void push_up(int l, int r, int o) {
    maxv[o] = maxv[o<<1];
    if(maxv[o].v < maxv[o<<1|1].v) maxv[o] = maxv[o<<1|1];
    if(maxv[o].v < last[o<<1].v + pre[o<<1|1].v) maxv[o]=node(last[o<<1].v+pre[o<<1|1].v, last[o<<1].l,pre[o<<1|1].r);
    else if(maxv[o].v == last[o<<1].v + pre[o<<1|1].v) {
        if(maxv[o].l > last[o<<1].l) maxv[o]=node(last[o<<1].v+pre[o<<1|1].v, last[o<<1].l,pre[o<<1|1].r);
        else if(maxv[o].l == last[o<<1].l) {
            if(maxv[o].r > pre[o<<1|1].r) maxv[o]=node(last[o<<1].v+pre[o<<1|1].v, last[o<<1].l,pre[o<<1|1].r);
        }
    }
    pre[o] = pre[o<<1];
    if(pre[o].v < sum[o<<1].v + pre[o<<1|1].v) pre[o] = node(sum[o<<1].v + pre[o<<1|1].v, sum[o<<1].l, pre[o<<1|1].r);
    else if(pre[o].v == sum[o<<1].v + pre[o<<1|1].v) {
        if(pre[o].r > pre[o<<1|1].r) pre[o] = node(sum[o<<1].v + pre[o<<1|1].v, l, pre[o<<1|1].r);
    }
    last[o] = last[o<<1|1];
    if(last[o].v < last[o<<1].v + sum[o<<1|1].v) last[o] = node(last[o<<1].v + sum[o<<1|1].v, last[o<<1].l, r);
    else if(last[o].v == last[o<<1].v + sum[o<<1|1].v) {
        if(last[o].l > last[o<<1].l) last[o] = node(last[o<<1].v + sum[o<<1|1].v, last[o<<1].l, r);
    }
    sum[o] = node(sum[o<<1].v + sum[o<<1|1].v, sum[o<<1].l, sum[o<<1|1].r);
}
void build(int l, int r, int o) {
    int m = (l + r) >> 1;
    maxv[o].v = pre[o].v = last[o].v = sum[o].v = -INF;
    if(l == r) {
        scanf("%lld", &maxv[o].v);
        maxv[o].l = maxv[o].r = l;
        sum[o] = pre[o] = last[o] = maxv[o];
        return ;
    }
    build(l, m, o<<1);
    build(m+1, r, o<<1|1);
    push_up(l, r, o);
}
node querysum(int L, int R, int l, int r, int o) {
    if(L <= l && r <= R) return sum[o];

    int m = (l + r) >> 1;
    int inf = 1e9 + 7;
    node ans = node(0, inf, -inf);
    if(L <= m) {
        ans = querysum(L, R, l, m, o<<1);
    }
    if(m < R) {
        node cur = querysum(L, R, m+1, r, o<<1|1);
        ans = node(ans.v+cur.v, min(ans.l,cur.l), max(ans.r,cur.r));
    }
    return ans;
}
node querypre(int L, int R, int l, int r, int o) {
    int m = (l + r) >> 1;
    if(L <= l && r <= R) return pre[o];
    node ans = node(-INF, 0, 0);
    if(m >= R) return querypre(L, R, l, m, o<<1);
    if(L > m) return querypre(L, R, m+1, r, o<<1|1);
    if(m >= L && m+1 <= R) {
        node cur1 = querypre(L, R, l, m, o<<1);
        node cur2 = querypre(L, R, m+1, r, o<<1|1);
        ans = cur1;
        node sum1 = querysum(L, R, l, m, o<<1);
        node hehe = node(sum1.v+cur2.v, sum1.l, cur2.r);
        if(ans.v < hehe.v) ans = hehe;
        else if(ans.v == hehe.v) {
            if(ans.l > hehe.l) ans = hehe;
            else if(ans.l == hehe.l) {
                if(ans.r > hehe.r) ans = hehe;
            }
        }
    }
    return ans;
}
node querylast(int L, int R, int l, int r, int o) {
    int m = (l + r) >> 1;
    if(L <= l && r <= R) return last[o];
    node ans = node(-INF, 0, 0);
    if(m >= R) return querylast(L, R, l, m, o<<1);
    if(L > m) return querylast(L, R, m+1, r, o<<1|1);
    if(m >= L && m+1 <= R) {
        node cur1 = querylast(L, R, l, m, o<<1);
        node cur2 = querylast(L, R, m+1, r, o<<1|1);
        ans = cur2;
        node sum2 = querysum(L, R, m+1, r, o<<1|1);
        node hehe = node(sum2.v+cur1.v, cur1.l, sum2.r);
        if(ans.v < hehe.v) ans = hehe;
        else if(ans.v == hehe.v) {
            if(ans.l > hehe.l) ans = hehe;
            else if(ans.l == hehe.l) {
                if(ans.r > hehe.r) ans = hehe;
            }
        }
    }
    return ans;
}
node query(int L, int R, int l, int r, int o) {
    int m = (l + r) >> 1;
    if(L <= l && r <= R) return maxv[o];
    node ans = node(-INF, 0, 0);
    if(m >= R) return query(L, R, l, m, o<<1);
    if(L > m) return query(L, R, m+1, r, o<<1|1);
    if(m >= L && m+1 <= R) {
        node cur1 = query(L, R, l, m, o<<1);
        node cur2 = query(L, R, m+1, r, o<<1|1);
        ans = cur1;
        if(ans.v < cur2.v) ans = cur2;
        else if(ans.v == cur2.v) {
            if(ans.l > cur2.l) ans = cur2;
            else if(ans.l == cur2.l) {
                if(ans.r > cur2.r) ans = cur2;
            }
        }
        node last1 = querylast(L, R, l, m, o<<1);
        node pre2 = querypre(L, R, m+1, r, o<<1|1);
        node hehe = node(last1.v+pre2.v, last1.l, pre2.r);
        if(ans.v < hehe.v) ans = hehe;
        else if(ans.v == hehe.v) {
            if(ans.l > hehe.l) ans = hehe;
            else if(ans.l == hehe.l) {
                if(ans.r > hehe.r) ans = hehe;
            }
        }
    }
    return ans;
}
int l, r, kase = 0;
int main() {
    while(~scanf("%d%d",&n, &m)) {
        build(1, n, 1);
        printf("Case %d:\n", ++kase);
        while(m--) {
            scanf("%d%d", &l, &r);
            node cur = query(l, r, 1, n, 1);
            printf("%d %d\n", cur.l, cur.r);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值