最小割树学习笔记

口胡

定义

对于一棵树,如果对于树上的所有边 (u,v)(u, v) , 满足去掉 (u,v)(u, v) 后产生的两个集合恰好是原图上 (u,v)(u, v) 的最小割把原图分成的两个集合, 且 (u,v)(u,v) 的权值是原图 (u,v)(u,v) 的最小割

构造

每次任选两个节点,求最小割,最小割把这张图分成了两个部分,然后对这两个部分分别递归构造, 复杂度 O(n3m)O(n^3m) , 跑不满。

性质

λ(a,b)\lambda(a, b) 表示 aabb 的最小割

性质 11

VuV_uVvV_v 表示边 (u,v)(u, v) 两端的部分, 那么对于 xVux \in V_uyVvy \in V_v, 有 λ(x,y)λ(u,v)\lambda(x, y) \leq \lambda(u, v) .

证明:

因为 xxyy 分别在被 (u,v)(u, v) 的最小割分成的两部分中,所以 λ(u,v)\lambda(u, v)(x,y)(x, y) 的割, 所以 λ(x,y)λ(u,v)\lambda(x, y) \leq \lambda(u, v)

性质 22

对于三个点 a,b,ca, b, c , 有 λ(a,b)min(λ(b,c),λ(a,c))\lambda(a, b) \geq \min(\lambda(b, c), \lambda(a, c))

证明:

在割掉 (a,b)(a, b) 后,cc 如果在 aa 那边,根据性质 11 , 有 λ(b,c)λ(a,b)\lambda(b, c) \leq \lambda(a, b) ,如果在 bb 那边, 有 λ(a,c)λ(a,b)\lambda(a, c) \leq \lambda(a, b) ,所以一定有 λ(a,b)min(λ(b,c),λ(a,c))\lambda(a, b) \geq \min(\lambda(b, c), \lambda(a, c))

性质 33

由性质 22 可以得到 λ(a,b)min(λ(a,p1),λ(p1,p2),λ(p2,p3),...λ(pk,b))\lambda(a, b) \geq \min(\lambda(a, p_1), \lambda(p_1, p_2), \lambda(p_2, p_3), ... \lambda(p_k, b))

性质 44 (最重要)

(p,q)(p, q) 为最小割树 xxyy 路径上的两点,且 λ(p,q)\lambda(p, q) 最小, 那么 λ(x,y)=λ(p,q)\lambda(x, y) = \lambda(p, q) , 即 λ(x,y)\lambda(x, y) 等于最小割树上 xxyy 的路径上权值最小的边.

证明:

因为 xxyy(p,q)(p,q) 两侧, 所以有 λ(x,y)λ(p,q)\lambda(x, y) \leq \lambda(p, q)

由性质 33λ(x,y)λ(p,q)\lambda(x, y) \geq \lambda(p, q)

所以 λ(x,y)=λ(p,q)\lambda(x, y) = \lambda(p, q)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//网络流
int bfs(int S, int T) {
memset(dep, 0, sizeof(dep));
memcpy(cur, head, sizeof(head));
q[h = t = 1] = S;
dep[S] = 1;
while (h <= t) {
int u = q[h++];
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (!dep[v] && c[i]) {
dep[v] = dep[u] + 1;
q[++t] = v;
}
}
}
return dep[T];
}

int dfs(int u, int T, int lim) {
if (u == T || !lim) return lim;
int flow = 0, k;
for (int i = cur[u]; i && lim; i = nxt[i]) {
cur[u] = i;
int v = to[i];
if (dep[v] == dep[u] + 1 && c[i]) {
k = dfs(v, T, min(lim, c[i]));
if (!k) dep[v] = 0;
lim -= k, flow += k;
c[i] -= k, c[i ^ 1] += k;
}
}
return flow;
}

int dinic(int S, int T) {
for (int i = 2; i <= e_tot; ++i) {
c[i] = c[i] + c[i ^ 1];
c[i ^ 1] = 0;
}
int res = 0;
while (bfs(S, T)) res += dfs(S, T, inf);
return res;
}

//构造最小割树
void solve(int l, int r) {
if (l == r) return ;
int S = node[l], T = node[l + 1];
int cut = dinic(S, T);
link(S, T, cut);
link(T, S, cut);
int tot1 = 0, tot2 = 0;
for (int i = l; i <= r; ++i) {
if (dep[node[i]]) tmp1[++tot1] = node[i];
else tmp2[++tot2] = node[i];
}
for (int i = 1; i <= tot1; ++i) node[l - 1 + i] = tmp1[i];
for (int i = 1; i <= tot2; ++i) node[l + tot1 - 1 + i] = tmp2[i];
solve(l, l + tot1 - 1);
solve(l + tot1, r);
}

void dfs(int u, int _fa) {
dep[u] = dep[_fa] + 1;
for (auto it : path[u]) {
int v = it.first, len = it.second;
if (v == _fa) continue;
minn[v][0] = len, fa[v][0] = u;
dfs(v, u);
}
}

// 查询任意两点的最小割
int query(int x, int y) {
int res = 0x3f3f3f3f;
if (dep[x] < dep[y]) swap(x, y);
for (int i = 10; ~i; --i) {
if (dep[fa[x][i]] >= dep[y]) {
res = min(res, minn[x][i]);
x = fa[x][i];
}
}
if (x == y) return res;
for (int i = 10; ~i; --i) {
if (fa[x][i] != fa[y][i]) {
res = min(res, minn[x][i]);
res = min(res, minn[y][i]);
x = fa[x][i];
y = fa[y][i];
}
}
res = min(res, minn[x][0]);
res = min(res, minn[y][0]);
return res;
}

例题

【模板】最小割树(Gomory-Hu Tree)

题目 代码

[ZJOI2011]最小割

题目 代码

[CQOI2016]不同的最小割

题目 代码