前言
事实证明,一个良好的语文水平是学习的基础。——— Sgzz.ssj.sse.ssl
简要题目
需
要
你
维
护
长
度
为
n
的
序
列
并
支
持
下
列
操
作
:
需要你维护长度为n的序列并支持下列操作:
需要你维护长度为n的序列并支持下列操作:
1.
区
间
加
法
;
1.区间加法;
1.区间加法;
2.
区
间
赋
值
;
2.区间赋值;
2.区间赋值;
3.
区
间
每
个
a
i
变
成
m
a
x
(
a
i
−
t
,
0
)
;
3.区间每个 ai 变成 max(ai−t,0);
3.区间每个ai变成max(ai−t,0);
4.
单
点
询
问
值
;
4.单点询问值;
4.单点询问值;
5.
单
点
询
问
历
史
最
大
值
;
5.单点询问历史最大值;
5.单点询问历史最大值;
n
,
m
≤
500000
,
其
中
m
为
操
作
数
。
n,m≤500000,其中 m 为操作数。
n,m≤500000,其中m为操作数。
首先我们的思路是:找到区间编号o,若本来区间有标记就计算,下放,再覆盖新的标记。但这里涉及到了一个问题:如果o的儿子也有标记,按照规定需要继续下放,如果儿子的儿子也有呢?
我们发现,这在时间上是行不通的。
然后,就有一个神奇的玩意儿:令每个节点的值为 m a x ( a + x , b ) max(a+x,b) max(a+x,b)。
可以分别实现操作1,2,3。
我们还可以证明这是可合并的:合并 ( a , b ) , ( c , d ) − − > ( a + c , m a x ( b + c , d ) ) (a,b),(c,d)-->(a+c,max(b+c,d)) (a,b),(c,d)−−>(a+c,max(b+c,d))
最后考虑下传标记。易知,父亲的信息必然在儿子的信息之后。
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 5e5 + 2;
const ll lim = (1ll << 62);
int n, m;
ll na[N << 2], nb[N << 2], ha[N << 2], hb[N << 2], ans1, ans2;
bool la[N << 2];
void build(const int o, const int l, const int r) {
if(l == r) {
scanf("%lld", &na[o]);
ha[o] = na[o];
return;
}
int mid = l + r >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
}
void pushDown(const int o) {
if(! la[o]) return;
int lson = (o << 1), rson = (o << 1 | 1);
la[lson] = la[rson] = 1;
ha[lson] = max(ha[lson], ha[o] + na[lson]);
ha[rson] = max(ha[rson], ha[o] + na[rson]);
hb[lson] = max(hb[lson], max(hb[o], nb[lson] + ha[o]));
hb[rson] = max(hb[rson], max(hb[o], nb[rson] + ha[o]));//为什么加ha[o]? 因为下放之后o的标记会清0,此时的ha一定在儿子获得值之后
nb[lson] = max(nb[o], na[o] + nb[lson]);
nb[rson] = max(nb[o], na[o] + nb[rson]);
na[lson] = max(na[lson] + na[o], -lim);
na[rson] = max(na[rson] + na[o], -lim);
na[o] = nb[o] = ha[o] = hb[o] = 0;
la[o] = 0;
}
void add(const int o, const int l, const int r, const int L, const int R, const ll k, const ll Lim) {
if(l > R || r < L) return;
if(l >= L && r <= R) {
na[o] = max(na[o] + k, -lim);
nb[o] = max(nb[o] + k, Lim);
ha[o] = max(ha[o], na[o]);
hb[o] = max(hb[o], nb[o]);
la[o] = 1;
return;
}
int mid = l + r >> 1;
pushDown(o);
add(o << 1, l, mid, L, R, k, Lim);
add(o << 1 | 1, mid + 1, r, L, R, k, Lim);
}
void ask(const int o, const int l, const int r, const int goal, const bool op) {
if(l > goal || r < goal) return;
if(l == r) {
ans1 = (op == 0 ? na[o] : ha[o]);
ans2 = (op == 0 ? nb[o] : hb[o]);
return;
}
pushDown(o);
int mid = l + r >> 1;
ask(o << 1, l, mid, goal, op);
ask(o << 1 | 1, mid + 1, r, goal, op);
}
int main() {
int op, l, r;
ll x;
scanf("%d %d", &n, &m);
build(1, 1, n);
while(m --) {
scanf("%d", &op);
if(op == 1) {
scanf("%d %d %lld", &l, &r, &x);
add(1, 1, n, l, r, x, 0);
}
else if(op == 2) {
scanf("%d %d %lld", &l, &r, &x);
add(1, 1, n, l, r, -x, 0);
}
else if(op == 3) {
scanf("%d %d %lld", &l, &r, &x);
add(1, 1, n, l, r, -lim, x);
}
else if(op == 4) {
scanf("%lld", &x);
ask(1, 1, n, x, 0);
printf("%lld\n", max(ans1, ans2));
}
else {
scanf("%lld", &x);
ask(1, 1, n, x, 1);
printf("%lld\n", max(ans1, ans2));
}
}
return 0;
}