支配树

本文最后更新于:星期四, 二月 3日 2022, 9:15 晚上

1. 定义

1.1 DAG上的支配树

作用:给定一个DAGDAG,询问从起点到终点必经的点,即去掉这个点以及与这个点相连的边,无法到达终点(无向图概念中的割点),可以建立支配树来求解

结构:树形结构,将图的起点作为根节点,每个节点都是到达根节点的必经点。

建图:

  • uu的在支配树上的父亲是所有能走到点uu在支配树上的LCALCA,于是可以通过O(nlogn)O(nlogn)复杂度通过倍增实现。
  • 具体来说,通过拓扑排序得到拓扑序,对于每个点根据反向边的LCALCA得到该点的父亲,从而建立DAGDAG上的支配树

2. 例题

2.1 BZOJ-2815-[ZJOI2012]灾难

模板题

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

#include <bits/stdc++.h>

using namespace std;

#define N 1000010
#define DEG 20

struct Graph {
struct Edge {
int to, nxt;

Edge() {}

Edge(int _to, int _nxt) {
to = _to;
nxt = _nxt;
}
} edge[N];

int head[N], tot;

void Init() {
memset(head, -1, sizeof head);
tot = 0;
}

void addedge(int u, int v) {
edge[tot] = Edge(v, head[u]);
head[u] = tot++;
}
} G[2], zp;

int n;
int fa[N][DEG], dep[N], du[N], sze[N];

struct Tree {
int LCA(int u, int v) {
if (u == -1) {
return v;
}
if (v == -1) {
return u;
}
if (dep[u] > dep[v]) {
swap(u, v);
}
for (int det = dep[v] - dep[u], i = 0; det; det >>= 1, ++i) {
if (det & 1) {
v = fa[v][i];
}
}
if (u == v) return u;
for (int i = DEG - 1; i >= 0; --i) {
if (fa[u][i] == fa[v][i]) {
continue;
}
u = fa[u][i];
v = fa[v][i];
}
return fa[u][0];
}

void DFS(int u) {
sze[u] = 1;
for (int i = zp.head[u]; ~i; i = zp.edge[i].nxt) {
int v = zp.edge[i].to;
if (sze[v] == 0) {
DFS(v);
}
sze[u] += sze[v];
}
}

void solve() {
queue<int> que;
vector<int> Q;
for (int i = 1; i <= n; ++i) {
if (du[i] == 0) {
que.push(i);
}
}
while (!que.empty()) {
int u = que.front();
que.pop();
Q.push_back(u);
for (int i = G[0].head[u]; ~i; i = G[0].edge[i].nxt) {
int v = G[0].edge[i].to;
--du[v];
if (du[v] == 0) {
que.push(v);
}
}
}
for (int i = 0, len = Q.size(); i < len; ++i) {
int u = Q[i];
int root = -1;
for (int j = G[1].head[u]; ~j; j = G[1].edge[j].nxt) {
int v = G[1].edge[j].to;
root = LCA(root, v);
}
if (root == -1) {
root = 0;
}
zp.addedge(root, u);
fa[u][0] = root;
dep[u] = dep[root] + 1;
for (int j = 1; j < DEG; ++j) {
if (fa[u][j - 1]) {
fa[u][j] = fa[fa[u][j - 1]][j - 1];
}
}
}
DFS(0);
}
} tree;

int main() {
scanf("%d", &n);
G[0].Init(), G[1].Init(), zp.Init();
for (int i = 1, x; i <= n; ++i) {
while (~scanf("%d", &x) && x) {
G[0].addedge(x, i);
G[1].addedge(i, x);
du[i]++;
}
}
tree.solve();
for (int i = 1; i <= n; ++i) {
printf("%d\n", sze[i] - 1);
}
return 0;
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!