LA 3938 动态最大连续和 线段树

时间:2023-03-09 00:41:11
LA 3938 动态最大连续和 线段树

题目链接:

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1939

来自:刘汝佳大白书P201.

解题思路:

构造一棵线段树,其中每个结点维护三个值,记录最大前缀和,最大后缀和最大连续和。

最大连续和要么完全在左段,要么完全在右段,要么在跨越中线。就是会是左段的最大后缀和+右段的最大前缀和。。。。

代码也是刘汝佳写的哦

代码:

 // LA3938 Ray, Pass me the dishes!
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int maxn = + ;
const int maxnode = + ;
typedef long long LL;
typedef pair<int,int> Interval; LL prefix_sum[maxn]; LL sum(int L, int R)
{
return prefix_sum[R] - prefix_sum[L-];
} LL sum(Interval p)
{
return sum(p.first, p.second);
} Interval better(Interval a, Interval b)
{
if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b;
return a < b ? a : b; // 利用pair自带的字典序
} int qL, qR; struct IntervalTree
{
int max_prefix[maxnode];
int max_suffix[maxnode];
Interval max_sub[maxnode]; void build(int o, int L, int R)
{
if(L == R)
{
max_prefix[o] = max_suffix[o] = L;
max_sub[o] = make_pair(L, L);
}
else
{
int M = L + (R-L)/;
// 递归创建子树
int lc = o*, rc = o*+;
build(lc, L, M);
build(rc, M+, R); // 递推max_prefix
LL v1 = sum(L, max_prefix[lc]);
LL v2 = sum(L, max_prefix[rc]);
if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]);
else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; // 递推max_suffix
v1 = sum(max_suffix[lc], R);
v2 = sum(max_suffix[rc], R);
if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]);
else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; // 递推max_sub
max_sub[o] = better(max_sub[lc], max_sub[rc]); // 完全在左子树或者右子树
max_sub[o] = better(max_sub[o], make_pair(max_suffix[lc], max_prefix[rc])); // 跨越中线
}
} Interval query_prefix(int o, int L, int R)
{
if(max_prefix[o] <= qR) return make_pair(L, max_prefix[o]);
int M = L + (R-L)/;
int lc = o*, rc = o*+;
if(qR <= M) return query_prefix(lc, L, M);
Interval i = query_prefix(rc, M+, R);
i.first = L;
return better(i, make_pair(L, max_prefix[lc]));
} Interval query_suffix(int o, int L, int R)
{
if(max_suffix[o] >= qL) return make_pair(max_suffix[o], R);
int M = L + (R-L)/;
int lc = o*, rc = o*+;
if(qL > M) return query_suffix(rc, M+, R);
Interval i = query_suffix(lc, L, M);
i.second = R;
return better(i, make_pair(max_suffix[rc], R));
} Interval query(int o, int L, int R)
{
if(qL <= L && R <= qR) return max_sub[o];
int M = L + (R-L)/;
int lc = o*, rc = o*+;
if(qR <= M) return query(lc, L, M);
if(qL > M) return query(rc, M+, R);
Interval i1 = query_prefix(rc, M+, R); // 右半的前缀
Interval i2 = query_suffix(lc, L, M); // 左半的后缀
Interval i3 = better(query(lc, L, M), query(rc, M+, R));
return better(make_pair(i2.first, i1.second), i3);
}
}; IntervalTree tree; int main()
{
int kase = , n, a, Q;
while(scanf("%d%d", &n, &Q) == )
{
prefix_sum[] = ;
for(int i = ; i < n; i++)
{
scanf("%d", &a);
prefix_sum[i+] = prefix_sum[i] + a;
}
tree.build(, , n);
printf("Case %d:\n", ++kase);
while(Q--)
{
int L, R;
scanf("%d%d", &L, &R);
qL = L;
qR = R;
Interval ans = tree.query(, , n);
printf("%d %d\n", ans.first, ans.second);
}
}
return ;
}

相关文章