【模板】树
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; } }