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

    核心思想:把树的结构变成链式,用线段树或者其他来处理问题

    做法:利用dfs来把树重新标号,每个非叶节点有一个重儿子,对于修改整棵子树的问题:因为新标号是dfs序的所以一定是一段区间,对于修改链的利用类似lca的方式每次将深度较大的节点搞到它重链的头上,并且处理该段重链,直到两个节点到同一重链上即可

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    const int N = 100010, M = N * 2;
    
    int n, m;
    int w[N], h[N], e[M], ne[M], idx;
    int id[N], nw[N], cnt;
    int dep[N], sz[N], top[N], fa[N], son[N];
    struct Tree
    {
        int l, r;
        LL add, sum;
    }tr[N * 4];
    
    void add(int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    void dfs1(int u, int father, int depth)
    {
        dep[u] = depth, fa[u] = father, sz[u] = 1;
        for (int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (j == father) continue;
            dfs1(j, u, depth + 1);
            sz[u] += sz[j];
            if (sz[son[u]] < sz[j]) son[u] = j;
        }
    }
    
    void dfs2(int u, int t)
    {
        id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;
        if (!son[u]) return;
        dfs2(son[u], t);
        for (int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (j == fa[u] || j == son[u]) continue;
            dfs2(j, j);
        }
    }
    
    void pushup(int u)
    {
        tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    }
    
    void pushdown(int u)
    {
        auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
        if (root.add)
        {
            left.add += root.add, left.sum += root.add * (left.r - left.l + 1);
            right.add += root.add, right.sum += root.add * (right.r - right.l + 1);
            root.add = 0;
        }
    }
    
    void build(int u, int l, int r)
    {
        tr[u] = {l, r, 0, nw[r]};
        if (l == r) return;
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
    
    void update(int u, int l, int r, int k)
    {
        if (l <= tr[u].l && r >= tr[u].r)
        {
            tr[u].add += k;
            tr[u].sum += k * (tr[u].r - tr[u].l + 1);
            return;
        }
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) update(u << 1, l, r, k);
        if (r > mid) update(u << 1 | 1, l, r, k);
        pushup(u);
    }
    
    LL query(int u, int l, int r)
    {
        if (l <= tr[u].l && r >= tr[u].r) return tr[u].sum;
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        LL res = 0;
        if (l <= mid) res += query(u << 1, l, r);
        if (r > mid) res += query(u << 1 | 1, l, r);
        return res;
    }
    
    void update_path(int u, int v, int k)
    {
        while (top[u] != top[v])
        {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            update(1, id[top[u]], id[u], k);
            u = fa[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        update(1, id[v], id[u], k);
    }
    
    LL query_path(int u, int v)
    {
        LL res = 0;
        while (top[u] != top[v])
        {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            res += query(1, id[top[u]], id[u]);
            u = fa[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        res += query(1, id[v], id[u]);
        return res;
    }
    
    void update_tree(int u, int k)
    {
        update(1, id[u], id[u] + sz[u] - 1, k);
    }
    
    LL query_tree(int u)
    {
        return query(1, id[u], id[u] + sz[u] - 1);
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
        memset(h, -1, sizeof h);
        for (int i = 0; i < n - 1; i ++ )
        {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b), add(b, a);
        }
        dfs1(1, -1, 1);
        dfs2(1, 1);
        build(1, 1, n);
    
        scanf("%d", &m);
        while (m -- )
        {
            int t, u, v, k;
            scanf("%d%d", &t, &u);
            if (t == 1)
            {
                scanf("%d%d", &v, &k);
                update_path(u, v, k);
            }
            else if (t == 2)
            {
                scanf("%d", &k);
                update_tree(u, k);
            }
            else if (t == 3)
            {
                scanf("%d", &v);
                printf("%lld
    ", query_path(u, v));
            }
            else printf("%lld
    ", query_tree(u));
        }
    
        return 0;
    }
    

      

  • 相关阅读:
    Python3之random模块常用方法
    Go语言学习笔记(九)之数组
    Go语言学习笔记之简单的几个排序
    Go语言学习笔记(八)
    Python3之logging模块
    Go语言学习笔记(六)
    123. Best Time to Buy and Sell Stock III(js)
    122. Best Time to Buy and Sell Stock II(js)
    121. Best Time to Buy and Sell Stock(js)
    120. Triangle(js)
  • 原文地址:https://www.cnblogs.com/cyq123/p/14226463.html
Copyright © 2011-2022 走看看