【数据结构】树上差分

给一棵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\n", i, A[i]);
    for (int i = 2; i <= n; ++i)
        printf("B[%d] = %d\n", i, B[i]);
}

对比

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

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

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

posted @ 2021-03-10 19:04  purinliang  阅读(63)  评论(0编辑  收藏  举报