题意:
在一个DAG中,问一个点是多少个点的支配点?
题解:
好像灭绝树就是因为这题被发明的。在DAG上拓扑排序时,通过在反图上倍增计算所有前驱的LCA,在新图(灭绝树)中add_edge(LCA,当前点)。最后对于每个点输出它在灭绝树上的子树大小-1(自己不算)。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=65540;
vector<int > g[MAXN],rg[MAXN],mg[MAXN];
int n,ind[MAXN],siz[MAXN];
int pre[MAXN],tot;
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int f[18][MAXN],dep[MAXN];
inline int lca(int x,int y) {
if (dep[x]<dep[y]) x^=y^=x^=y;
int t=dep[x]-dep[y];
for (int i=0;i<18;++i)
if (t&(1<<i)) x=f[i][x];
if (x==y) return x;
for (int i=17;~i;--i)
if (f[i][x]^f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
inline void topological_sort() {
queue<int > q;
while (!q.empty()) q.pop();
g[0].clear(),mg[0].clear(),dep[0]=0;
for (register int i=1;i<=n;++i)
if (!ind[i]) q.push(i),dep[i]=1,g[0].push_back(i),rg[i].push_back(0),f[0][i]=0;
while (!q.empty()) {
tot=0;
int cur=q.front();
q.pop();
for (int i=0;i<rg[cur].size();++i) {
int v=rg[cur][i];
pre[++tot]=v;
}
int anc=pre[1];
for (int i=2;i<=tot;++i) anc=lca(anc,pre[i]);
dep[cur]=dep[anc]+1;
f[0][cur]=anc;
// printf("%d->%d\n",anc,cur);
mg[anc].push_back(cur);
for (int i=1;i<18;++i) f[i][cur]=f[i-1][f[i-1][cur]];
for (int i=0;i<g[cur].size();++i) {
int v=g[cur][i];
--ind[v];
if (!ind[v]) q.push(v);
}
}
}
void dfs(int p) {
siz[p]=1;
for (int i=0;i<mg[p].size();++i) {
int v=mg[p][i];
if (v^f[0][p])
dfs(v),siz[p]+=siz[v];
}
}
int main() {
// freopen("bzoj 2815.in","r",stdin);
memset(ind,0,sizeof(ind));
n=read();
for (register int i=1;i<=n;++i) g[i].clear(),rg[i].clear(),mg[i].clear();
for (register int i=1;i<=n;++i) {
while (1) {
int x=read();
if (!x) break;
++ind[i];
g[x].push_back(i),rg[i].push_back(x);
}
}
topological_sort();
dfs(0);
for (register int i=1;i<=n;++i) printf("%d\n",siz[i]-1);
return 0;
}