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;
}
posted @ 2017-02-24 18:50  pbvrvnq  阅读(181)  评论(0编辑  收藏  举报