UOJ164 线段树历史最值查询
对于线段树的历史查询我们可以用一个二元组
定义(a, b)表示+a对b取max
我们用二元组(a, b), (c, d)分别表示当前以及历史的标记;
注意顺序的问题很重要,提醒一下重载运算符会很方便,还要注意负无穷相加得太多会爆,合并时对标记-oo取max很有必要,好像很抽象,那我在代码里注释一下,防止大家被坑。。。。
#include <cstring>
#include <cstdio>
typedef long long LL;
const LL oo = 1LL << 60;
const int MXN = 2e6 + 10;
#define rep(i, s, t) for(int i = s; i <= t; ++i)
template<class T>
T max(T x, T y) {return x>y?x:y;}
template<class T>
T read(T x = 0, T f = 1) {
char c = getchar();
while(c < '0' || c > '9') f = c=='-'?-1:1, c = getchar();
while(c >= '0' && c <= '9') x = x*10 + c-'0', c = getchar();
return x * f;
}
int n, m;
namespace Segment_Tree {
struct Tag {
LL a, b;
Tag() {a = 0; b = -oo;}
LL big() {return max(a, b);}
void CLR() {a = 0; b = -oo;}
Tag link(LL _a, LL _b) {a = _a, b = _b; return *this;}
}T[MXN], G, H[MXN];
Tag operator + (Tag p, Tag s) {
Tag New;
return New.link(max(s.a+p.a, -oo), max(s.b+p.a, p.b));
//notice :: max(~, -oo)!!!!!
}
Tag operator ^ (Tag p, Tag s) {
Tag New;
return New.link(max(p.a, s.a), max(p.b, s.b));
}
#define l(h) h<<1
#define r(h) h<<1|1
void push_down(int h) {
H[l(h)] = (H[h] + T[l(h)]) ^ H[l(h)];
H[r(h)] = (H[h] + T[r(h)]) ^ H[r(h)];
T[l(h)] = T[h] + T[l(h)];
T[r(h)] = T[h] + T[r(h)];
T[h].CLR();
H[h].CLR();
}
/*
(x, -oo)
(-x, 0)
(-oo, x)
*/
void build(int h, int L, int R) {
if(L == R) {
H[h] = T[h].link(read<LL>(), -oo);
return ;
}
int M = (L + R) >> 1;
build(l(h), L, M);
build(r(h), M+1, R);
}
void update(int h, int L, int R, int u, int v) {
if(u <= L && R <= v) {
T[h] = G + T[h];
H[h] = H[h] ^ T[h];
}else {
push_down(h);
int M = (L + R) >> 1;
if(u <= M) update(l(h), L, M, u, v);
if(v > M) update(r(h), M+1, R, u, v);
}
}
LL query(int h, int L, int R, int u, bool f) {
if(L == R)
return f? T[h].big() : H[h].big();
push_down(h);
int M = (L + R) >> 1;
if(u <= M) return query(l(h), L, M, u, f);
else return query(r(h), M+1, R, u, f);
}
};
using namespace Segment_Tree;
void input() {
n = read<int>(), m = read<int>();
build(1, 1, n);
}
void output() {
rep(i, 1, m) {
int type = read<int>();
if(type <= 3) {
int u = read<int>(), v = read<int>();
LL x = read<LL>();
if(type == 1) G.link(x, -oo);
else if(type == 2) G.link(-x, 0);
else if(type == 3) G.link(-oo, x);
update(1, 1, n, u, v);
}else {
int u = read<int>();
LL Ans = query(1, 1, n, u, type==4);
printf("%lld\n", Ans);
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("res.out", "w", stdout);
#endif
input();
output();
return 0;
}