UOJ164 线段树历史最值查询

来源:互联网 发布:行业的选择 知乎 编辑:程序博客网 时间:2024/05/16 19:40

对于线段树的历史查询我们可以用一个二元组

定义(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;}
0 0