现在的位置: 首页 > 综合 > 正文

LA3938——线段树区间合并

2013年09月26日 ⁄ 综合 ⁄ 共 2870字 ⁄ 字号 评论关闭

题意:给定一个长度为n的序列,每次询问一个区间[a, b],求出该区间内最大连续和的范围。

维护线段树节点的5个域:l, r区间的左右端点;x, y最大连续和的范围的左右端点;ln最大前缀和的右端点;rn最大后缀和的左端点。在区间合并的时候,分情况讨论,不详述。

查询的时候,如果待查询区间“横跨”了所在区间的中点,分三种情况讨论:最大连续和在左区间,在右区间,以及跨区间中点。对于跨区间中点的情况,要应用另外一种查询方式,即查询在范围内的最大前缀和以及最大后缀和。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define lng long long
#define lson(x) (x << 1)
#define rson(x) (x << 1) | 1
using namespace std;

const int maxn = 500000 + 10;
struct node
{
    int l, r;
    int x, y;
    int ln, rn;
}tree[maxn];
int n, m;
lng sum[maxn];

void pushup(int now)
{
    lng tmp = sum[tree[rson(now)].ln] - sum[tree[lson(now)].rn - 1];
    tree[now].x = tree[lson(now)].rn; tree[now].y = tree[rson(now)].ln;
    lng ltmp = sum[tree[lson(now)].y] - sum[tree[lson(now)].x - 1];
    if(ltmp >= tmp) { tmp = ltmp; tree[now].x = tree[lson(now)].x; tree[now].y = tree[lson(now)].y; }
    lng rtmp = sum[tree[rson(now)].y] - sum[tree[rson(now)].x - 1];
    if(rtmp > tmp) { tmp = rtmp; tree[now].x = tree[rson(now)].x; tree[now].y = tree[rson(now)].y; }
    tree[now].ln = tree[lson(now)].ln;
    lng a = sum[tree[now].ln] - sum[tree[now].l - 1], b = sum[tree[rson(now)].ln] - sum[tree[now].l - 1];
    if(b > a) tree[now].ln = tree[rson(now)].ln;
    tree[now].rn = tree[rson(now)].rn;
    a = sum[tree[now].r] - sum[tree[now].rn - 1]; b = sum[tree[now].r] - sum[tree[lson(now)].rn - 1];
    if(b >= a) tree[now].rn = tree[lson(now)].rn;
}

void build(int l, int r, int now)
{
    tree[now].l = l; tree[now].r = r;
    if(l == r) { tree[now].x = l; tree[now].y = r; tree[now].ln = r; tree[now].rn = l; }
    else
    {
        int mid = (l + r) >> 1;
        build(l, mid, lson(now));
        build(mid + 1, r, rson(now));
        pushup(now);
    }
    //printf("%d %d %d %d %d %d\n", l, r, tree[now].x, tree[now].y, tree[now].ln, tree[now].rn);
}

int queryl(int x, int now)
{
    if(x >= tree[now].ln) return tree[now].ln;
    int mid = (tree[now].l + tree[now].r) >> 1;
    if(x <= mid) { return queryl(x, lson(now)); }
    else
    {
        int tmp = queryl(x, rson(now));
        lng a = sum[tmp] - sum[tree[now].l - 1], b = sum[tree[lson(now)].ln] - sum[tree[now].l - 1];
        if(a > b) return tmp;
        else return tree[lson(now)].ln;
    }
}

int queryr(int x, int now)
{
    if(x <= tree[now].rn) return tree[now].rn;
    int mid = (tree[now].l + tree[now].r) >> 1;
    if(x > mid) { return queryr(x, rson(now)); }
    else
    {
        int tmp = queryr(x, lson(now));
        lng a = sum[tree[now].r] - sum[tmp - 1], b = sum[tree[now].r] - sum[tree[rson(now)].rn - 1];
        if(a >= b) return tmp;
        else return tree[rson(now)].rn;
    }
}

void query(int l, int r, int now, int & x, int & y)
{
    if(l <= tree[now].l && r >= tree[now].r) { x = tree[now].x; y = tree[now].y; return;}
    else
    {
        int mid = (tree[now].l + tree[now].r) >> 1;
        if(r <= mid) { query(l, r, lson(now), x, y); }
        else if(l > mid) { query(l, r, rson(now), x, y); }
        else
        {
            int tmpx = queryr(l, lson(now)), tmpy = queryl(r, rson(now));
            lng tmp = sum[tmpy] - sum[tmpx - 1];
            query(l, mid, lson(now), x, y);
            lng ltmp = sum[y] - sum[x - 1];
            if(ltmp >= tmp) { tmpx = x; tmpy = y; tmp = ltmp; }
            query(mid + 1, r, rson(now), x, y);
            lng rtmp = sum[y] - sum[x - 1];
            if(rtmp > tmp) { tmpx = x; tmpy = y; tmp = rtmp; }
            x = tmpx; y = tmpy;
        }
    }
}

int main()
{
    freopen("in", "r", stdin);
    int cc = 1;
    while(~scanf("%d %d", &n, &m))
    {
        sum[0] = 0;
        for(int i = 1; i <= n; ++i)
        {
            int a; scanf("%d", &a);
            sum[i] = sum[i - 1] + a;
        }
        build(1, n, 1);
        printf("Case %d:\n", cc++);
        while(m--)
        {
            int a, b, x, y; scanf("%d %d", &a, &b);
            query(a, b, 1, x, y);
            printf("%d %d\n", x, y);
        }
    }
    return 0;
}

/*
3 1 
1 2 3 
1 1

Case 1: 
1 1
*/

抱歉!评论已关闭.