題目
分析
將圖中所有邊取反,發現要求的就是每個點支配的點數。然而發現一個問題:這個不是一個單源點的有向圖。我們只需建一個源點,將其向所有入度爲零的點連邊,建出支配樹即可。
當然,這個圖是 DAG,事實上拓撲排序就 + LCA 能找到支配點。但我還是用的 LT
錯因
- 沒想到怎麼處理多源點的 DAG 的問題;
- 板子打錯了兩個地方。
代碼
#include <bits/stdc++.h>
const int MAXN = 65534;
int N;
int In[MAXN + 5];
std::vector<int> G[MAXN + 5], H[MAXN + 5];
std::vector<int> STree[MAXN + 5], ITree[MAXN + 5];
int DfnCnt;
int Fat[MAXN + 5];
int Dfn[MAXN + 5], Tid[MAXN + 5];
int SDom[MAXN + 5], IDom[MAXN + 5];
struct Union_Find {
int Fat[MAXN + 5], Min[MAXN + 5];
void Init(int n) {
for (int i = 1; i <= n; i++)
Fat[i] = Min[i] = i;
}
int Find(int u) {
if (Fat[u] == u)
return u;
int anc = Find(Fat[u]);
if (Dfn[SDom[Min[Fat[u]]]] < Dfn[SDom[Min[u]]])
Min[u] = Min[Fat[u]];
return Fat[u] = anc;
}
}T;
void Dfs(int u) {
Tid[Dfn[u] = ++DfnCnt] = u;
for (int i = 0; i < int(G[u].size()); i++) {
int v = G[u][i];
if (!Dfn[v])
Fat[v] = u, Dfs(v);
}
}
void Lengauer_Tarjan() {
for (int i = DfnCnt; i >= 2; i--) {
int u = Tid[i];
for (int j = 0; j < int(H[u].size()); j++) {
int v = H[u][j];
if (Dfn[v]) {
T.Find(v);
if (Dfn[SDom[T.Min[v]]] < Dfn[SDom[u]])
SDom[u] = SDom[T.Min[v]];
}
}
STree[SDom[u]].push_back(u);
int r = T.Fat[u] = Fat[u];
for (int j = 0; j < int(STree[r].size()); j++) {
int v = STree[r][j];
T.Find(v);
if (SDom[T.Min[v]] == r)
IDom[v] = r;
else
IDom[v] = T.Min[v];
}
STree[r].clear();
}
for (int i = 2; i <= DfnCnt; i++) {
int u = Tid[i];
if (IDom[u] != SDom[u])
IDom[u] = IDom[IDom[u]];
}
}
int Size[MAXN + 5];
void Count(int u) {
Size[u] = 1;
for (int i = 0; i < int(ITree[u].size()); i++) {
int v = ITree[u][i];
Count(v);
Size[u] += Size[v];
}
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
while (1) {
int v; scanf("%d", &v);
if (!v) break;
In[i]++;
G[v].push_back(i);
H[i].push_back(v);
}
}
for (int i = 1; i <= N; i++)
if (!In[i]) {
G[N + 1].push_back(i);
H[i].push_back(N + 1);
}
Dfs(N + 1);
for (int i = 1; i <= N + 1; i++)
SDom[i] = i;
T.Init(N + 1);
Lengauer_Tarjan();
for (int i = 1; i <= N + 1; i++)
if (IDom[i])
ITree[IDom[i]].push_back(i);
Count(N + 1);
for (int i = 1; i <= N; i++)
printf("%d\n", Size[i] - 1);
return 0;
}