zoukankan      html  css  js  c++  java
  • 【数据结构】树上差分

    给一棵n个节点的树,覆盖m条树链,统计每个顶点和每条边被覆盖了多少次。

    dfs1:标记深度、子树大小、找重儿子
    dfs2:轻重链剖分
    chain:覆盖一条树链
    calc:统计每个顶点和每条边被覆盖了多少次

    const int MAXN = 3e5 + 5;
    
    int n, m;
    vector<int> G[MAXN];
    
    int dep[MAXN], siz[MAXN], mch[MAXN], pat[MAXN], top[MAXN];
    
    void dfs1(int u, int p) {
        dep[u] = dep[p] + 1, siz[u] = 1, mch[u] = 0, pat[u] = p;
        for (int v : G[u]) {
            if (v == p)
                continue;
            dfs1(v, u);
            siz[u] += siz[v];
            if (siz[v] > siz[mch[u]])
                mch[u] = v;
        }
    }
    
    void dfs2(int u, int p, int t) {
        top[u] = t;
        if (mch[u])
            dfs2(mch[u], u, t);
        for (int v : G[u]) {
            if (v == p || v == mch[u])
                continue;
            dfs2(v, u, v);
        }
    }
    
    int lca(int u, int v) {
        for (; top[u] != top[v]; u = pat[top[u]]) {
            if (dep[top[u]] < dep[top[v]])
                swap(u, v);
        }
        return (dep[u] <= dep[v]) ? u : v;
    }
    
    int A[MAXN], B[MAXN];
    
    void chain(int x, int y) {
        int z = lca(x, y);
        ++A[x], ++A[y], --A[z];
        if (pat[z])
            --A[pat[z]];
        ++B[x], ++B[y], B[z] -= 2;
    }
    
    void calc(int u, int p) {
        for (int v : G[u]) {
            if (v == p)
                continue;
            calc(v, u);
            A[u] += A[v];
            B[u] += B[v];
        }
    }
    
    void solve() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            G[i].clear();
            A[i] = 0, B[i] = 0;
        }
        for (int i = 1; i <= n - 1; ++i) {
            int x, y;
            scanf("%d%d", &x, &y);
            G[x].emplace_back(y);
            G[y].emplace_back(x);
        }
        dfs1(1, 0);
        dfs2(1, 0, 1);
        for (int i = 1; i <= m; ++i) {
            int x, y;
            scanf("%d%d", &x, &y);
            chain(x, y);
        }
        calc(1, 0);
        for (int i = 1; i <= n; ++i)
            printf("A[%d] = %d
    ", i, A[i]);
        for (int i = 2; i <= n; ++i)
            printf("B[%d] = %d
    ", i, B[i]);
    }
    

    对比

    树上差分:关键是快速找LCA的算法,可以使用树上倍增、轻重链剖分、Tarjan等不同处理。一般是O(nlogn)解决链修改之后的静态查询问题,但要求修改操作存在逆元。(貌似可以在另一棵树上修改达到子树修改的效果)

    轻重链剖分+线段树:O(nlog2n)解决链修改、子树修改的动态查询问题,不需要操作存在逆元。

    LCT:O(nlogn)解决链修改的动态查询问题,不需要操作存在逆元。

  • 相关阅读:
    JS变量的作用域
    使用jquery修改css中带有!important的样式属性
    js异步加载的三种解决方案
    js 停止事件冒泡 阻止浏览器的默认行为(阻止超连接 # )
    【翻译】MongoDB指南/CRUD操作(二)
    【翻译】MongoDB指南/CRUD操作(一)
    【翻译】MongoDB指南/引言
    深入浅出UML类图(一)
    让thinkphp 5 支持pathinfo 的 nginx ,去掉index.php
    linux 常用命令
  • 原文地址:https://www.cnblogs.com/purinliang/p/14513614.html
Copyright © 2011-2022 走看看