UVALive - 3938 (线段树,区间查询)

本文介绍了一种基于线段树的数据结构实现方法,用于快速求解区间内最大子段和的问题。通过预处理和递归构建线段树,能够高效地处理区间查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:详细分析见训练指南P200。注意可能答案的起点在左区间,终点在右区间


AC代码

#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 500000+5;

int dish[maxn];
LL psum[maxn];

LL sum(int l, int r) {
    return psum[r] - psum[l-1];
}

LL sum(pii a) {
    return psum[a.second] - psum[a.first-1];
}

pii better(pii a, pii b) {
    if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b;
    return a < b ? a : b;
}

struct node{
    pii sub;
    int prefix, suffix;
}tree[maxn<<2];

void build(int l, int r, int o) {
    if(l == r) {
        tree[o].sub = make_pair(l, l);
        tree[o].prefix = tree[o].suffix = l;
        return;
    } else {
        int mid = (l+r) / 2;
        int lc = o*2, rc = o*2+1;
        //创建子树
        build(l, mid, lc);
        build(mid+1, r, rc);
        //递推prefix
        LL v1 = sum(l, tree[lc].prefix);
        LL v2 = sum(l, tree[rc].prefix);
        if(v1 >= v2) {
            tree[o].prefix = tree[lc].prefix;
        } else {
            tree[o].prefix = tree[rc].prefix;
        }

        //递推suffix
        v1 = sum(tree[lc].suffix, r);
        v2 = sum(tree[rc].suffix, r);
        if(v1 >= v2) {
            tree[o].suffix = tree[lc].suffix;
        } else {
            tree[o].suffix = tree[rc].suffix;
        }

        //递推sub
        tree[o].sub = better(tree[lc].sub, tree[rc].sub);
        tree[o].sub = better(tree[o].sub, make_pair(tree[lc].suffix, tree[rc].prefix));
    }
}

int qL, qR;
pii query_prefix(int o, int l, int r) {
    if(tree[o].prefix <= qR) return make_pair(l, tree[o].prefix);
    int mid = (l+r)/2;
    int lc = o*2, rc = o*2+1;
    if(qR <= mid) {
        return query_prefix(lc, l, mid);
    } else {
        pii i = query_prefix(rc, mid+1, r);
        i.first = l;
        return better(i, make_pair(l, tree[lc].prefix));
    }
}

pii query_suffix(int o, int l, int r) {
    if(tree[o].suffix >= qL) return make_pair(tree[o].suffix, r);
    int mid = (l+r)/2;
    int lc = o*2, rc = o*2+1;
    if(qL >= mid+1) {
        return query_suffix(rc, mid+1, r);
    } else {
        pii i = query_suffix(lc, l, mid);
        i.second = r;
        return better(i, make_pair(tree[rc].suffix, r));
    }
}

pii query(int o, int l, int r) {
    if(qL <= l && r <= qR) return tree[o].sub;
    int mid = (l+r)/2;
    int lc = o*2, rc = o*2+1;
    if(qR <= mid) return query(lc, l, mid);
    if(qL > mid) return query(rc, mid+1, r);
    pii i1 = query_prefix(rc, mid+1, r); //右半的前缀
    pii i2 = query_suffix(lc, l, mid); //左半的后缀
    pii i3 = better(query(lc, l, mid), query(rc, mid+1, r));
    return better(i3, make_pair(i2.first, i1.second));
}

int main() {
    int n, m, kase = 1;
    while(scanf("%d%d", &n, &m) == 2) {
        psum[0] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &dish[i]);
            psum[i] = psum[i-1] + dish[i];
        }
        build(1, n, 1);
        printf("Case %d:\n", kase++);
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &qL, &qR);
            pii ans = query(1, 1, n);
            printf("%d %d\n", ans.first, ans.second);
        }
    }

    return 0;
}

如有不当之处欢迎指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值