【模板】树

1 深度优先搜索 (dfs,大法师)

// implementation 1
void dfs(int x){
    int i, y;
    // do something
    for(i = first[x]; i; i = next[i])
        if((y = to[i]) != p[x]){
            p[y] = x;
            // do something
            dfs(y);
            // do something
        }
    // do something
}

// implementation 2
void dfs(int x, int px){
    int i, y;
    // do something
    for(i = first[x]; i; i = next[i])
        if((y = to[i]) != px){
            // do something
            dfs(y, x);
            // do something
        }
    // do something
}

2 最近公共祖先 (LCA) 的倍增算法 (树上倍增的基本模板)

void dfs(int x) {
    int i, y;
    for (i = 0; P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
    for (i = first[x]; i; i = next[i])
        if ((y = to[i]) != p[x])
            p[y] = x, dep[y] = dep[x] + 1, dfs(y);
}

int jump_until(int x, int d) {
    for (int i = LN - 1; i >= 0; --i)
        if (dep[x] - (1 << i) >= d)
            x = P[i][x];
    return x;
}

int LCA(int x, int y) {
    if (dep[x] < dep[y]) std::swap(x, y);
    if (x = jump_until(x, dep[y]), x == y) return x;
    for (int i = LN - 1; i >= 0; --i)
        if (P[i][x] != P[i][y])
            x = P[i][x], y = P[i][y];
    return p[x];
}

3 最近公共祖先 (LCA)  ST 表算法

int cnt, id[N], st[20][M], *ord = *st;

inline int dmin(const int x, const int y) {return dep[x] < dep[y] ? x : y;}

void dfs(int x, int px = 0) {
    int i, y;
    ord[cnt] = x; id[x] = cnt++;
    for (i = first[x]; i; i = next[i])
        if ((y = to[i]) != px)
            dep[y] = dep[x] + 1, dfs(y, x), ord[cnt++] = x;
}

void build_st_table() {
    int *f, *g = ord, i, j, k = cnt;
    for (j = 0; 1 << j + 1 <= cnt; ++j) {
        f = g; g = st[j + 1]; k -= 1 << j;
        for (i = 0; i < k; ++i)
            g[i] = dmin(f[i], f[i + (1 << j)]);
    }
}

inline int LCA(int x, int y) {
    int L = std::min(id[x], id[y]), R = (id[x] ^ id[y] ^ L) + 1, c = lg2(R - L);
    return dmin(st[c][L], st[c][R - (1 << c)]);
}

4 轻重链剖分 (Heavy-Light Decomposition)

int p[N], dep[N], size[N];
int cnt = 0, id[N], prf[N], top[N];

void dfs_wt(int x) {
    int i, y, &z = prf[x]; size[x] = !next[first[x]];
    for (i = first[x]; i; i = next[i])
        if ((y = to[i]) != p[x]) {
            p[y] = x, dep[y] = dep[x] + 1;
            dfs_wt(y), size[x] += size[y];
            size[y] > size[z] ? z = y : 0;
        }
}

void dfs_hld(int x, int r) {
    int i, y; id[x] = ++cnt, top[x] = r;
    if (!prf[x]) return;
    dfs_hld(prf[x], r);
    for (i = first[x]; i; i = next[i])
        if (!top[y = to[i]]) dfs_hld(y, y);
}

int solve(int u, int v) {
    int x = top[u], y = top[v];
    for (; x != y; u = p[x], x = top[u]) {
        if (dep[x] < dep[y]) {swap(u, v); swap(x, y);}
        // do something on [x, u]
    }
    if (dep[u] > dep[v]) {swap(u, v); swap(lx, ly);}
    // do something on [u, v]
    // return something
}

5 树分治 (静态点分治)

namespace Centroid {
    int V, Gm, G, size[N];

    void init(int _V) {V = _V; Gm = INT_MAX;}

    int get(int x, int px = 0) {
        int i, y, Max = 0; size[x] = 1;
        for (i = first[x]; i; i = next[i])
            if ((y = to[i]) != px && !fy[y]) {
                get(y, x); up(Max, size[y]);
                size[x] += size[y];
            }
        up(Max, V - size[x]);
        return Max <= Gm ? (Gm = Max, G = x) : G;
    }
}

#define get_centroid(x, y) (Centroid::init(y), Centroid::get(x))

void dfs(int x, int px = 0, int dep = 1) {
    int i, y; size[x] = 1;
    for (i = first[x]; i; i = next[i])
        if ((y = to[i]) != px && !fy[y])
            dfs(y, x, dep + 1), size[x] += size[y];
}

void solve(int x) {
    int i, y, G;
    fy[x] = 1; dfs(x);
    // do something
    for (i = first[x]; i; i = next[i])
        if (!fy[y = to[i]])
            G = get_centroid(y, size[y]), solve(G);
}

// main
G = get_centroid(1, n); solve(G);

6 虚树 (深度栈算法)

int cnt_vir, vir[N], virp[N];

inline bool idcmp(const int x, const int y) {return id[x] < id[y];}

void DSA(int n, int *v) {
    #define ins(x) (virp[x] = stack[top], stack[++top] = vir[cnt_vir++] = x)
    int i, x, y, top = 0; cnt_vir = 0;
    for (i = 0; i < n; ++i)
        if (x = v[i], !top) {
            for (; top; --top) stack[top] = 0; ins(x);
        } else {
            stack[top + 1] = 0;
            for (y = LCA(x, stack[top]); dep[ stack[top] ] > dep[y]; --top);
            virp[ stack[top + 1] ] = y;
            if (stack[top] != y) ins(y); ins(x);
        }
    for (; top; --top) stack[top] = 0;
    std::sort(vir, vir + cnt_vir, idcmp);
}

7 长链剖分 (Long-Short Decomposition)

void dfs_len(int x) {
    int i, y, &z = prf[x];
    for (i = 0; i < LN && P[i][x]; ++i) P[i + 1][x] = P[i][P[i][x]];
    for (i = first[x]; i; i = next[i])
        if ((y = to[i]) != p[x]) {
            p[y] = x; dep[y] = dep[x] + 1;
            dfs_len(y);
            up(f[x], f[y] + 1);
            f[y] > f[z] ? z = y : 0;
        }
}

void dfs_lsd(int x, int r, int l = 1) { // long-short decomposition
    int i, y;
    id[x] = ++cnt; top[x] = r;
    if (!prf[x]) {len[x] = l; return;}
    dfs_lsd(prf[x], r, l + 1); len[x] = len[prf[x]];
    for (i = first[x]; i; i = next[i])
        if (!top[y = to[i]])
            dfs_lsd(y, y);
}

int ancestor(int x, int k) {
    if (dep[x] < k) return 0;
    if (!k) return x;
    int i = lg2(k); x = P[i][x]; k ^= 1 << i;
    if (!k) return x;
    i = dep[x] - dep[top[x]] - k;
    return near[top[x]][i];
}

void init() {
    int i, j, x, *pt;
    *f = *dep = -1; dfs_len(1); dfs_lsd(1, 1);
    for (i = 1; i < N; ++i)
        if (top[i] == i) {
            near[i] = (new int[len[i] * 2 + 1]) + len[i]; pt = near[i]; *pt = i;
            for (j = 1, x = p[i]; j <= len[i] && x; ++j, x = p[x]) pt[-j] = x;
            for (j = 1, x = prf[i]; j <= len[i] && x; ++j, x = prf[x]) pt[j] = x;
        }
}

猜你喜欢

转载自www.cnblogs.com/lau1997/p/12665758.html
今日推荐