洛谷传送门
BZOJ传送门
题目背景
小新经常陪小白去公园玩,也就是所谓的遛狗啦…
题目描述
在小新家附近有一条“公园路”,路的一边从南到北依次排着 n n 个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第 个和第 b b 个公园之间(包括 、 b b 两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
输入输出格式
输入格式:
第一行,两个整数 和
M
M
,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来 行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来
M
M
行,每行三个整数。第一个整数 ,
1
1
或 。
- K=1 K = 1 表示,小新要带小白出去玩,接下来的两个整数 a a 和 给出了选择公园的范围( 1≤a,b≤N 1 ≤ a , b ≤ N );
-
K=2
K
=
2
表示,小白改变了对某个公园的打分,接下来的两个整数
p
p
和 ,表示小白对第
p
p
个公园的打分变成了 (
1≤p≤N
1
≤
p
≤
N
)。
其中, 1≤N≤500000 1 ≤ N ≤ 500 000 , 1≤M≤100000 1 ≤ M ≤ 100 000 ,所有打分都是绝对值不超过 1000 1000 的整数。
输出格式:
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
输入输出样例
输入样例#1:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3
输出样例#1:
2
-1
解题分析
线段树的基础操作, 维护区间最大子段和。 要实现这个我们只需要维护区间和、区间左端开始的最大和、区间右端开始的最大和即可。(想一想为什么)
很坑的是这里有 a>b a > b 的情况, 博主 MLE M L E 了几次才发现….
代码如下:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 500050
#define ls (now << 1)
#define rs (now << 1 | 1)
bool neg;
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
W (!isdigit(c))
{if(c == '-') neg = true; c = gc;}
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
if(neg) neg = false, x = -x;
}
int dot, q;
int dat[MX];
struct Node
{
int fl, fr, mx, tot;
void init(R int now)
{fl = fr = mx = tot = now;}
}tree[MX << 3];
namespace SGT
{
IN void pushup(R int now)
{
tree[now].tot = tree[ls].tot + tree[rs].tot;
tree[now].fl = std::max(tree[ls].fl, tree[ls].tot + tree[rs].fl);
tree[now].fr = std::max(tree[rs].fr, tree[rs].tot + tree[ls].fr);
tree[now].mx = std::max(std::max(tree[ls].mx, tree[rs].mx), tree[rs].fl + tree[ls].fr);
}
void build(R int now, R int lef, R int rig)
{
if(lef == rig) return tree[now].init(dat[lef]);
int mid = lef + rig >> 1;
build(ls, lef, mid), build(rs, mid + 1, rig);
pushup(now);
}
void modify(R int now, R int lef, R int rig, R int tar, R int val)
{
if(lef == rig) return tree[now].init(val);
int mid = lef + rig >> 1;
if(tar <= mid) modify(ls, lef, mid, tar, val);
else modify(rs, mid + 1, rig, tar, val);
pushup(now);
}
Node query(R int now, R int lef, R int rig, R int lb, R int rb)
{
if(lef >= lb && rig <= rb) return tree[now];
int mid = lef + rig >> 1;
if(lb > mid) return query(rs, mid + 1, rig, lb, rb);
else if(rb <= mid) return query(ls, lef, mid, lb, rb);
else//像pushup一样合并区间信息
{
Node l = query(ls, lef, mid, lb, rb);
Node r = query(rs, mid + 1, rig, lb, rb);
Node ret;
ret.mx = std::max(std::max(l.mx, r.mx), l.fr + r.fl);
ret.tot = l.tot + r.tot;
ret.fr = std::max(l.fr + r.tot, r.fr);
ret.fl = std::max(r.fl + l.tot, l.fl);
return ret;
}
}
}
int main(void)
{
int typ, a, b;
in(dot), in(q);
for (R int i = 1; i <= dot; ++i) in(dat[i]);
SGT::build(1, 1, dot);
W (q--)
{
in(typ), in(a), in(b);
if(typ & 1) {if(a > b) std::swap(a, b); printf("%d\n", SGT::query(1, 1, dot, a, b).mx);}
else SGT::modify(1, 1, dot, a, b);
}
}