心得
题意很简单就不过多叙述,这个题对个人最大的启发就是,在我们写线段树时,设计变量时一定要考虑清楚。
当前设置的变量能不能把答案算出,如果不能我们就要再定义额外的变量,然后再看额外的变量能不能计算出来,不能再开变量,直到所有的都能够被计算出来为止。
以本题举例:我们要算[L, R]区间最大的字段连续的和,如果我们只是设置一个表达字段和的变量tmax,如果当这段区间出现跨区间的现象我们就凭这一个变量是无法算出答案的,所以我们在来设置每个区间的前缀最大值,和后缀最大值,但是我们要计算父节点的前缀最大值和后缀最大值时,我们又将面临一个跨区间的问题,所以我们再对于没一个区间设置一个区间和的变量,那么我么所设置的所有变量都将可以得到计算得出。
代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
#define xx first
#define yy second
using namespace std;
typedef pair<int, int> PII;
const int N = 5e5+10, INF = 1e9 + 10;
int n, m;
int arr[N];
struct node
{
int l, r;
int sum;
int lmax, rmax, tmax;
}tr[N*4];
void pushup (node &u, node &l, node &r)
{
u.sum = l.sum+r.sum;
u.lmax = max(l.lmax, l.sum+r.lmax);
u.rmax = max(r.rmax, r.sum+l.rmax);
u.tmax = max(max(l.tmax, r.tmax), l.rmax+r.lmax);
}
void pushup(int u)
{
pushup(tr[u], tr[u<<1], tr[u << 1 | 1]);
}
void build(int u, int l, int r)
{
if(l == r) tr[u] = {l, r, arr[r], arr[r], arr[r], arr[r]};
else
{
tr[u] = {l,r};
int mid = l+r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid+1, r);
pushup(u);
}
}
void modify(int u, int x, int v)
{
if(tr[u].l == x && tr[u].r == x) tr[u] = {x, x, v, v, v, v};
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
node query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u];
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(l > mid) return query(u << 1 | 1, l, r);
else if(r <= mid)return query(u << 1, l, r);
else
{
auto left = query(u << 1, l, r);
auto right = query(u << 1 | 1, l, r);
node tree;
pushup(tree, left, right);
return tree;
}
}
}
signed main()
{
IOS;
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> arr[i];
build(1, 1, n);
while(m--)
{
int op, l, r;
cin >> op >> l >> r;
if(op == 1)
{
if(l > r) swap(l, r);
cout << query(1, l, r).tmax << endl;
}
else modify(1, l, r);
}
return 0;
}