题意:给定一个长度为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
*/