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;
}
}