题意是给出一个序列以及下标a,b
让你输出满足a<=x<=y<=b的二元组(x, y)
使得该范围内的序列和在(a,b)中最大
这道题的思路是分情况合并子线段
其实这道题的复杂程度在于你选择的数据存储类型
我刚开始就是在线段树中记录太多东西了,写到后来写懵了
看了别人的代码才知道,记录序列的前缀和会省掉很多力气
而且在query中递归用PushUp的方法也很新奇
代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 500005
#define LL long long
using namespace std;
LL a[MAXN];
LL sum[MAXN];
struct NODE {
int prefix, suffix;//前缀、后缀
int x, y;//该段的左右边界
int subx, suby;//该段最大和对应的左右边界
};
NODE node[MAXN*2+1];
void PushUp(int l, int r, int rt) {
NODE &tmp = node[rt];
int L = rt<<1;
int R = rt<<1|1;
tmp.x = l;
tmp.y = r;
tmp.prefix = sum[node[L].prefix]-sum[l-1] >= sum[node[R].prefix]-sum[l-1] ? node[L].prefix : node[R].prefix;
tmp.suffix = sum[r]-sum[node[L].suffix-1] >= sum[r]-sum[node[R].suffix-1] ? node[L].suffix : node[R].suffix;
if(sum[node[L].suby]-sum[node[L].subx-1] >= sum[node[R].suby]-sum[node[R].subx-1]) {
tmp.suby = node[L].suby;
tmp.subx = node[L].subx;
} else {
tmp.suby = node[R].suby;
tmp.subx = node[R].subx;
}
if(sum[node[R].prefix]-sum[node[L].suffix-1] > sum[tmp.suby]-sum[tmp.subx-1]) {
tmp.subx = node[L].suffix;
tmp.suby = node[R].prefix;
} else if(sum[node[R].prefix]-sum[node[L].suffix-1] == sum[tmp.suby]-sum[tmp.subx-1]) {
if(tmp.subx > node[L].suffix||(tmp.subx == node[L].suffix && tmp.suby > node[R].prefix)) {
tmp.subx = node[L].suffix;
tmp.suby = node[R].prefix;
}
}
}
void build(int l, int r, int rt) {
NODE &tmp = node[rt];
if(l == r) {
tmp.x = l;
tmp.y = l;
tmp.prefix = l;
tmp.suffix = l;
tmp.subx = tmp.suby = l;
return ;
}
int m = (l+r)>>1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
PushUp(l, r, rt);
}
void query(int rt, int L, int R, int &ansx, int &ansy, int &prefix, int &suffix) {
int l = node[rt].x;
int r = node[rt].y;
if(L<=l && R>=r) {
ansx = node[rt].subx;
ansy = node[rt].suby;
prefix = node[rt].prefix;
suffix = node[rt].suffix;
return ;
}
int m = (l+r)>>1;
if(R <= m) query(rt<<1, L, R, ansx, ansy, prefix, suffix);
else if(L > m) query(rt<<1|1, L, R, ansx, ansy, prefix, suffix);
else {
int x1, x2, y1, y2, p1, p2, s1, s2;
query(rt<<1, L, m, x1, y1, p1, s1);
query(rt<<1|1, m+1, R, x2, y2, p2, s2);
prefix = sum[p1]-sum[L-1] >= sum[p2]-sum[L-1] ? p1 : p2 ;
suffix = sum[R]-sum[s1-1] >= sum[R]-sum[s2-1] ? s1 : s2 ;
if(sum[y1]-sum[x1-1] >= sum[y2]-sum[x2-1]) {
ansx = x1;
ansy = y1;
}
else {
ansx = x2;
ansy = y2;
}
LL LS = sum[m]-sum[s1-1];
LL RS = sum[p2]-sum[m];
if(LS+RS > sum[ansy]-sum[ansx-1] || (LS+RS == sum[ansy]-sum[ansx-1] && ansx > s1) || (LS+RS == sum[ansy]-sum[ansx-1] && ansx == s1 && ansy > p2))
{
ansx = s1;
ansy = p2;
}
}
}
int main(void) {
int m, n, _, L, R;
_ = 1;
while(~scanf("%d%d", &n, &m)) {
for(int i=1; i<=n; ++i) {
scanf("%lld", &a[i]);
sum[i] = sum[i-1]+a[i];
}
build(1, n, 1);
printf("Case %d:\n", _++);
int ansx, ansy, prefix, suffix;
while(m--) {
scanf("%d%d", &L, &R);
query(1, L, R, ansx, ansy, prefix, suffix);
printf("%d %d\n", ansx, ansy);
}
}
return 0;
}