模板树链剖分

Posted blog-fgy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板树链剖分相关的知识,希望对你有一定的参考价值。

题目链接:https://loj.ac/problem/139

#include <iostream>
#include <cstdio>
#define LL long long
#define Re register
#define min(a, b) (a < b ? a : b)
#define max(a, b) (a > b ? a : b)
#define maxN 100005
inline LL read() {
    LL x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == -)
            f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x * f;
}
using namespace std;
LL Ans;
struct Segment_Tree {
    int l, r, tag;
    LL sum;
#define ls (rt << 1)
#define rs (rt << 1 | 1)
} t[maxN << 2];
struct Edge {
    int nxt, to;
} e[maxN << 1];
int cnte = 1, head[maxN];
inline void add_Edge(int i, int j) { e[++cnte].nxt = head[i], e[cnte].to = j, head[i] = cnte; }
int N, val[maxN], M, root, tot, siz[maxN], hson[maxN], top[maxN], num[maxN], dfn[maxN], dep[maxN], fa[maxN];
void dfs1(int u, int FA) {
    fa[u] = FA, siz[u] = 1, dep[u] = dep[FA] + 1;
    for (int v, i = head[u]; i; i = e[i].nxt) {
        if ((v = e[i].to) == FA)
            continue;
        dfs1(v, u), siz[u] += siz[v];
        if (siz[v] > siz[hson[u]])
            hson[u] = v;
    }
}
void dfs2(int u, int TOP) {
    dfn[u] = ++tot, num[dfn[u]] = u, top[u] = TOP;
    if (!hson[u])
        return;
    dfs2(hson[u], TOP);
    for (Re int i = head[u]; i; i = e[i].nxt) {
        Re int v = e[i].to;
        if (v != fa[u] && v != hson[u])
            dfs2(v, v);
    }
}
inline void pushup(int rt) { t[rt].sum = t[ls].sum + t[rs].sum; }
inline void pushdown(int rt) {
    if (!t[rt].tag)
        return;
    t[ls].sum += (t[ls].r - t[ls].l + 1) * t[rt].tag;
    t[rs].sum += (t[rs].r - t[rs].l + 1) * t[rt].tag;
    t[ls].tag += t[rt].tag, t[rs].tag += t[rt].tag;
    t[rt].tag = 0;
}
void Build_Tree(int rt, int l, int r) {
    t[rt].l = l, t[rt].r = r;
    if (l == r) {
        t[rt].sum = val[num[l]];
        return;
    }
    int mid = (l + r) >> 1;
    Build_Tree(ls, l, mid), Build_Tree(rs, mid + 1, r);
    pushup(rt);
}
void update(int rt, int l, int r, int c) {
    if (l <= t[rt].l && t[rt].r <= r) {
        t[rt].tag += c;
        t[rt].sum += (t[rt].r - t[rt].l + 1) * c;
        return;
    }
    pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1;
    if (l <= mid)
        update(ls, l, r, c);
    if (mid < r)
        update(rs, l, r, c);
    pushup(rt);
}
LL query(int rt, int l, int r) {
    if (l <= t[rt].l && t[rt].r <= r)
        return t[rt].sum;
    pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1;
    LL ret = 0;
    if (l <= mid)
        ret += query(ls, l, r);
    if (mid < r)
        ret += query(rs, l, r);
    return ret;
}
void update_path(int x, int y, int k) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            x ^= y ^= x ^= y;
        update(1, dfn[top[x]], dfn[x], k);
        x = fa[top[x]];
    }
    update(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), k);
}
void Q_path(int x, int y) {
    Ans = 0;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            x ^= y ^= x ^= y;
        Ans += query(1, dfn[top[x]], dfn[x]);
        x = fa[top[x]];
    }
    Ans += query(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]));
}
int LCA(int x, int y) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            x ^= y ^= x ^= y;
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
int find(int x, int y) {
    while (top[x] != top[y]) {
        if (fa[top[y]] == x)
            return top[y];
        y = fa[top[y]];
    }
    return hson[x];
}
void Q_tree(int u) {
    if (LCA(root, u) != u)
        Ans = query(1, dfn[u], dfn[u] + siz[u] - 1);
    else if (u == root)
        Ans = t[1].sum;
    else {
        int s = find(u, root);
        Ans = t[1].sum - query(1, dfn[s], dfn[s] + siz[s] - 1);
    }
}
void update_tree(int u, int k) {
    if (LCA(root, u) != u)
        update(1, dfn[u], dfn[u] + siz[u] - 1, k);
    else if (root == u)
        update(1, 1, tot, k);
    else {
        int s = find(u, root);
        update(1, 1, tot, k);
        update(1, dfn[s], dfn[s] + siz[s] - 1, -k);
    }
}
int main() {
    N = read();
    for (Re int i = 1; i <= N; ++i) val[i] = read();
    for (Re int i = 2; i <= N; ++i) {
        Re int x = read();
        add_Edge(i, x), add_Edge(x, i);
    }
    dfs1(1, 0), dfs2(1, 1);
    Build_Tree(1, 1, tot);
    M = read();
    while (M--) {
        int u, v, k;
        int opt = read();
        if (opt == 1)
            root = read();
        if (opt == 2) {
            u = read(), v = read(), k = read();
            update_path(u, v, k);
        }
        if (opt == 3) {
            u = read(), k = read();
            update_tree(u, k);
        }
        if (opt == 4) {
            u = read(), v = read();
            Q_path(u, v);
            printf("%lld
", Ans);
        }
        if (opt == 5) {
            u = read();
            Q_tree(u);
            printf("%lld
", Ans);
        }
    }
    return 0;
}

 

以上是关于模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

模板时间◆模板·II◆ 树链剖分

树链剖分模板题(luogu3384 模板树链剖分)

树链剖分模板

BZOJ 2243--染色(树链剖分)

模板树链剖分

luoguP3384 模板树链剖分