luogu P4513ybtoj线段树课堂过关例题3小白逛公园
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P4513ybtoj线段树课堂过关例题3小白逛公园相关的知识,希望对你有一定的参考价值。
Link
luogu P4513 小白逛公园
ybtoj【线段树课堂过关】【例题3】小白逛公园
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了
题目大意
给你一个序列,要维护两个操作。
单点修改和在一个区间中找权值最大的子区间的权值。
解题思路
第一次学习这种模板(也有可能不是第一次😅)
找一个最大的区间,可以想到用 左子树的最大后缀 + 右子树的最大前缀 拼在一起
每个节点多加上三个附加值——
l
s
u
m
,
r
s
u
m
,
s
u
m
lsum,rsum,sum
lsum,rsum,sum,就是左子树的最大后缀, 右子树的最大前缀,最大区间
为了保证最大后缀和最大前缀能拼在一起,这两个缀必须加上对方…
t
r
e
e
[
r
o
o
t
∗
2
]
.
r
s
u
m
+
t
r
e
e
[
r
o
o
t
∗
2
+
1
]
.
s
tree[root * 2].rsum + tree[root * 2 + 1].s
tree[root∗2].rsum+tree[root∗2+1].s=>最大后缀
t
r
e
e
[
r
o
o
t
∗
2
+
1
]
.
l
s
u
m
+
t
r
e
e
[
r
o
o
t
∗
2
]
.
s
tree[root * 2 + 1].lsum + tree[root * 2].s
tree[root∗2+1].lsum+tree[root∗2].s=>最大前缀
Code
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
struct DT{
ll s, lsum, rsum, sum;
}tree[4001000];
int n, m, a[500100], c, x, y;
void up(int root) {
tree[root].s = tree[root * 2].s + tree[root * 2 + 1].s;
tree[root].lsum = max(tree[root * 2].lsum, tree[root * 2].s + tree[root * 2 + 1].lsum);
tree[root].rsum = max(tree[root * 2 + 1].rsum, tree[root * 2 + 1].s + tree[root * 2].rsum);
tree[root].sum = max(max(tree[root * 2].sum, tree[root * 2 + 1].sum), tree[root * 2].rsum + tree[root * 2 + 1].lsum);
}
void build(int root, int l, int r) {
if(l == r) {
tree[root].s = a[l];
tree[root].lsum = tree[root].rsum = tree[root].sum = a[l];
return;
}
int mid = (l + r) / 2;
build(root * 2, l, mid);
build(root * 2 + 1, mid + 1, r);
up(root);
}
DT find(int root, int l, int r, int x, int y) {
if(x <= l && r <= y)
return tree[root];
int mid = (l + r) / 2;
//目标区间在一边
if(y <= mid) return find(root * 2, l, mid, x, y);
if(x > mid) return find(root *2 + 1, mid + 1, r, x, y);
//目标区间分两半
DT now;
DT now1 = find(root * 2, l, mid, x, y);
DT now2 = find(root * 2 + 1, mid + 1, r, x, y);
now.s = now1.s + now2.s;
now.lsum = max(now1.lsum, now1.s + now2.lsum);
now.rsum = max(now2.s + now1.rsum, now2.rsum);
now.sum = max(max(now1.sum, now2.sum), now1.rsum + now2.lsum);
return now;
}
void change(int root, int l, int r, int x, int y) {
if(l == r) {
tree[root].s = y;
tree[root].lsum = tree[root].rsum = tree[root].sum = y;
return;
}
int mid = (l + r) / 2;
if(x <= mid)
change(root * 2, l, mid, x, y);
else
change(root * 2 + 1, mid + 1, r, x, y);
up(root);
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
build(1, 1, n);
for(int i = 1; i <= m; i++) {
scanf("%d %d %d", &c, &x, &y);
if(c == 1) {
if(x > y) swap(x, y);
printf("%lld\\n", find(1, 1, n, x, y).sum);
}else change(1, 1, n, x, y);
}
}
以上是关于luogu P4513ybtoj线段树课堂过关例题3小白逛公园的主要内容,如果未能解决你的问题,请参考以下文章
ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口
luogu UVA10559 ybtoj 区间DP课堂过关 例题3消除木块 & 方块消除 Blocks
luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色