zoukankan      html  css  js  c++  java
  • 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
    ", Ans);
            }
        }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("input.in", "r", stdin);
        freopen("res.out", "w", stdout);
    #endif
        input();
        output();
        return 0;
    }
  • 相关阅读:
    OC内存管理
    摘要算法
    加密算法
    编码技术
    Golang遇到的一些问题总结
    SignalR
    uni-app 小程序 vue
    C# 调用 C++ dll的两种方式
    Vue 项目 VSCode 调试
    Navicat 导出 表结构
  • 原文地址:https://www.cnblogs.com/pbvrvnq/p/8530150.html
Copyright © 2011-2022 走看看