一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
题目描述
A - Segment Tree, part 2 -Segment with the Maximum Sum
There is an array of n elements, initially filled with zeros. You need to write a data structure that processes two types of queries:
assign value v to all elements on the segment from l to r−1, find the segment with maximal sum.
Input
The first line contains two numbers n and m (1≤n,m≤100000), the size of the array and the number of operations. The following lines contain the description of the operations. The description of each operation is as follows: l r v: assign the value v to all elements on the interval from l to r−1 (0≤l<r≤n, −109≤v≤109).
Output
Print m lines: the maximum sum of numbers on a segment after each operation. Please note that this segment may be empty (so the sum on it will be equal to 0).
Example
input
5 3
0 5 3
1 3 -1
3 4 -5
output
15
7
3
问题解析
这题建议去写一下基础版单点修改:A - Segment Tree, part 1 - Codeforces
题目是说给你一个全为0的数组,每次操作给区间l~r的数都改成v,每次修改完后输出当前数组的最大子数组和(也可以一个数都不选,那就是0)。
这种计算最大子段和,我们要维护四个数,一个是从区间左边向右延申得到的最大子段和:lmax,一个数从区间右边向左延申得到的最大子段和rmax,一个是当前区间的最大子段和:date,一个是区间的和:f。
一个区间的最大子段和,要么是左子节点的最大子段和,要么是右子节点的最大子段和,要么是右节点的rmax+左节点的lmax。
一个区间的最大左子段和,要么是左子节点的左子段和,要么是右子节点的左子段和+左节点的区间的和f。
一个区间的最大右子段和,要么是右子节点的右子段和,要么是左子节点的右子段和+右节点的区间和f。
每次修改的时候顺便修改这四个数值即可,最后整个区间的最大子段和就存在date[1]里。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 100500;
const ll NO_OP = 1e18;
ll f[4 * N], b[4 * N], lmax[4 * N], rmax[4 * N], date[4 * N];
void push_down(ll k, ll l, ll r)
{
if (b[k] != NO_OP)
{
int m = (l + r) / 2;
b[k + k] = b[k];
b[k + k + 1] = b[k];
f[k + k] = (m - l + 1) * b[k];
lmax[k + k] = max((ll)0, f[k + k]);
rmax[k + k] = max((ll)0, f[k + k]);
date[k + k] = max((ll)0, f[k + k]);
f[k + k + 1] = (r - m) * b[k];
lmax[k + k + 1] = max((ll)0, f[k + k + 1]);
rmax[k + k + 1] = max((ll)0, f[k + k + 1]);
date[k + k + 1] = max((ll)0, f[k + k + 1]);
b[k] = NO_OP;
}
}
void revise(ll k, ll l, ll r, ll x, ll y, ll v)
{
if (l == x && r == y)
{
b[k] = v;
f[k] = (r - l + 1) * v;
date[k] = (r - l + 1) * v;
lmax[k] = (r - l + 1) * v;
rmax[k] = (r - l + 1) * v;
return;
}
push_down(k, l, r);
int m = (l + r) / 2;
if (y <= m)revise(k + k, l, m, x, y, v);
else
if (x > m)revise(k + k + 1, m + 1, r, x, y, v);
else
{
revise(k + k, l, m, x, m, v);
revise(k + k + 1, m + 1, r, m + 1, y, v);
}
f[k] = f[k + k] + f[k + k + 1];
lmax[k] = max(lmax[k + k], f[k + k] + lmax[k + k + 1]);
rmax[k] = max(rmax[k + k + 1], f[k + k + 1] + rmax[k + k]);
date[k] = max(max(date[k + k], date[k + k + 1]), rmax[k + k] + lmax[k + k + 1]);
}
int main()
{
int n, m;
cin >> n >> m;
memset(b, NO_OP, sizeof b);
while (m--)
{
ll x, y, v;
cin >> x >> y >> v;
revise(1, 1, n, x + 1, y, v);
cout << max((ll)0,date[1]) << endl;
}
return 0;
}