zoukankan      html  css  js  c++  java
  • 树链剖分

    下面给出能够完成下列操作的一份树剖代码

    • 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

    • 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

    • 3 x z 表示将以x为根节点的子树内所有节点值都加上z

    • 4 x 表示求以x为根节点的子树内所有节点值之和

    /*
    *TODO
    *---- Galaxy
    */
    #include <cstdio>
    #include <cstring>
    
    typedef long long LL;
    
    const int MAXN = 1e6 + 10;
    const int MAXM = 2e5 + 10;
    #define rep(i, s, t) for(int i = s; i <= t; ++i)
    #define erep(i, u) for(int i = Begin[u]; i ^ (-1); i = Next[i])
    
    template<class T> void swap(T &x, T &y) {x ^= y ^= x ^= y;}
    
    #define C c = getchar()
    inline LL read(LL x = 0, int f = 1) {
        char C;
        while(c < '0' || c > '9') f = c=='-'?-1:1, C;
        while(c >= '0' && c <= '9') x = x * 10 + c-'0', C;
        return x * f;
    }
    
    int n, m, Root, a[MAXN];
    LL Mod;
    
    namespace Galaxy {
        int e, to[MAXM], Begin[MAXN], Next[MAXN];
        int _, Id[MAXN], End[MAXN];
        int sz[MAXN], dep[MAXN], hson[MAXN], fa[MAXN], top[MAXN];
    
    #define FILL(a, b) memset(a, b, sizeof a)
        void init() {
            e = _ = 0;
            FILL(Begin, -1);
        }
    
        void Add(int x, int y) {
            to[e] = y;
            Next[e] = Begin[x];
            Begin[x] = e++;
        }
    
        void dfs(int u) {
            int v;
            sz[u] = 1;
            erep(i, u)
                if((v=to[i]) ^ fa[u]) {
                    fa[v] = u;
                    dep[v] = dep[u] + 1;
                    dfs(v);
                    if(sz[v] > sz[hson[u]]) hson[u] = v;
                    sz[u] += sz[v];
                }
        }
    
        //XXX
        void DFS(int u, int Top) {
            top[u] = Top; Id[u] = ++_;
            erep(i, u)
                if(to[i] == hson[u])
                    DFS(to[i], Top);
    
            int v;
            erep(i, u)
                if(!top[v=to[i]])
                    DFS(v, v);
            End[u] = _;
        }
    
    #define l(h) (h<<1)
    #define r(h) (h<<1|1)
        LL sum[MAXN << 2], add[MAXN << 2];
    
        void push_up(int h, int L, int R) {
            sum[h] = (sum[l(h)] + sum[r(h)]) % Mod;
            sum[h] = (sum[h] + add[h] * (R-L+1)) % Mod;
        }
    
        void update(int h, int u, int v, int L, int R, LL Tmp) {
            if(u <= L && R <= v) add[h] = (add[h] + Tmp) % Mod;
            else {
                int M = (L + R) >> 1;
                if(u <= M) update(l(h), u, v, L, M, Tmp);
                if(v > M) update(r(h), u, v, M+1, R, Tmp);
            }
    
            push_up(h, L, R);
        }
    
        LL query(int h, int u, int v, int L, int R, LL _add) {
            if(L >= u && R <= v)
                return (sum[h] + _add * (R-L+1) % Mod) % Mod;
    
            int M = (L + R) >> 1;
            LL ret = 0;
            if(u <= M) ret = (ret + query(l(h), u, v, L, M, _add+add[h])) % Mod;
            if(v > M) ret = (ret + query(r(h), u, v, M+1, R, _add+add[h])) % Mod;
    
            return ret % Mod;
        }
    
        void TC(int u, int v, int w) {
            for(; top[u] ^ top[v]; u = fa[top[u]]) {
                if(dep[top[u]] < dep[top[v]]) swap(u, v);
                update(1, Id[top[u]], Id[u], 1, n, w);
            }
            if(Id[u] > Id[v]) swap(u, v);
            update(1, Id[u], Id[v], 1, n, w);
        }
    
        LL TQ(int u, int v) {
            LL ret = 0;
    
            for(; top[u] ^ top[v]; u = fa[top[u]]) {
                if(dep[top[u]] < dep[top[v]]) swap(u, v);
                ret = (ret + query(1, Id[top[u]], Id[u], 1, n, 0)) % Mod;
            }
            if(dep[u] > dep[v]) swap(u, v);
            ret = (ret + query(1, Id[u], Id[v], 1, n, 0)) % Mod;
    
            return ret % Mod;
        }
    };
    using namespace Galaxy;
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("input.in", "r", stdin);
        freopen("res.out", "w", stdout);
    #endif
        init();
    
        n = read(), m = read(), Root = read(), Mod = read();
        rep(i, 1, n) a[i] = read() % Mod;
        rep(i, 1, n-1) {
            int u = read(), v = read();
            Add(u, v), Add(v, u);
        }
    
        dfs(Root);
        DFS(Root, Root);
        rep(i, 1, n) update(1, Id[i], Id[i], 1, n, a[i]);
    
        rep(i, 1, m) {
            int type = read(), u, v, w;
            if(type == 1) {
                u = read(), v = read(), w = read();
                TC(u, v, w);
            }else if(type == 2) {
                u = read(), v = read();
                printf("%lld
    ", TQ(u, v));
            }else if(type == 3) {
                u = read(), w = read();
                update(1, Id[u], End[u], 1, n, w);
            }else if(type == 4) {
                u = read();
                printf("%lld
    ", query(1, Id[u], End[u], 1, n, 0));
            }
        }
        return 0;
    }
  • 相关阅读:
    【CF720D】Slalom 扫描线+线段树
    【CF724F】Uniformly Branched Trees 动态规划
    【CF725G】Messages on a Tree 树链剖分+线段树
    【CF736D】Permutations 线性代数+高斯消元
    【CF799E】Aquarium decoration 线段树
    【CF739E】Gosha is hunting 贪心
    【CF744D】Hongcow Draws a Circle 二分+几何
    【BZOJ3774】最优选择 最小割
    【BZOJ2138】stone Hall定理+线段树
    【BZOJ4445】[Scoi2015]小凸想跑步 半平面交
  • 原文地址:https://www.cnblogs.com/pbvrvnq/p/8530148.html
Copyright © 2011-2022 走看看