支配树:满足树上任何一点的所有祖先都是他的支配点的树.
支配点:在图中指定一个起点s,若删去一个点t,s到w就没有路径,则t为w的支配点.
-
一棵树本身就是支配树
-
对于DAG:
- 在原图上拓扑排序.
- 按照拓扑序建支配树,方法是求出所有原图上有边指向该节点的点(即反图上该节点指向的点)的支配树上lca,将该节点设为lca的子结点,顺便更新深度,fa数组等信息.
- dfs求出每个点的子树size.
- 结果即为每个点子树(不含该点)的size.
-
对于一般图:
- 去问tarjan.
-
#include <iostream> #include <cstdio> #include <queue> using namespace std; const int N = 100005; int n, x; int rin[N], head[3][N * 2], cnt[3], index[N], dep[N], fa[N][21], siz[N]; queue<int> q; struct edge { int to, next; } e[3][N * 2]; void add(int u, int v, int type) { e[type][++cnt[type]].to = v; e[type][cnt[type]].next = head[type][u]; head[type][u] = cnt[type]; } void topo() { for (int i = 1; i <= n; i++) if (!rin[i]) q.push(i); int tot = 0; while (!q.empty()) { int x = q.front(); q.pop(); index[++tot] = x; for (int i = head[0][x]; i; i = e[0][i].next) { int v = e[0][i].to; rin[v]--; if (!rin[v]) q.push(v); } } } int lca(int a, int b) { if (dep[a] > dep[b]) swap(a, b); for (int i = 20; i >= 0; i--) if (dep[fa[b][i]] >= dep[a]) b = fa[b][i]; if (a == b) return a; for (int i = 20; i >= 0; i--) if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return fa[a][0]; } void dfs(int k) { for (int i = head[2][k]; i; i = e[2][i].next) { int v = e[2][i].to; dfs(v); siz[k] += siz[v]; } siz[k]++; } int main() { ios::sync_with_stdio(false); cin >> n; for (int i = 1; i <= n; i++) { while (1) { cin >> x; if (x == 0) break; rin[i]++; add(x, i, 0); add(i, x, 1); } } topo(); for (int i = 1; i <= n; i++) { int ans = e[1][head[1][index[i]]].to; for (int j = head[1][index[i]]; j; j = e[1][j].next) ans = lca(ans, e[1][j].to); add(ans, index[i], 2); dep[index[i]] = dep[ans] + 1; fa[index[i]][0] = ans; for (int j = 1; j <= 20; j++) fa[index[i]][j] = fa[fa[index[i]][j - 1]][j - 1]; } dfs(0); for (int i = 1; i <= n; i++) cout << siz[i] - 1<<endl; }