题目链接:Stable Members
这道题似乎可以拓扑排序+染色做。我不会,于是直接支配树了。
我们让支配树的唯一源点为0点,然后建立反图,根据支配树的定义可知,每个点的支配点为祖先。
所以这些点不被支配,则只有一个祖先就是0点,所以其实就是找0点的儿子。
由于要求最近支配点,不能0点,所以我们让0点为n+1即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10,M=N*20;
int n,s;
struct Dominate_tree{
int cnt,tot,res;
int head[N<<1],pre[N<<1],to[M<<1],nex[M<<1],lat[M],cdy[M];
int bel[M],val[M],sdom[M],idom[M];
int dfn[M],id[M],fa[M];
inline void add(int *head,int a,int b){
to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
void dfs(int x){
dfn[x]=++cnt; id[cnt]=x;
for(int i=head[x];i;i=nex[i]){
if(dfn[to[i]]) continue;
dfs(to[i]); fa[to[i]]=x;
}
}
int find(int x){
if(x==bel[x]) return x;
int rt=find(bel[x]);
if(dfn[sdom[val[bel[x]]]]<dfn[sdom[val[x]]]) val[x]=val[bel[x]];
return bel[x]=rt;
}
void Tarjan(){
for(int i=cnt;i>=2;i--){
int x=id[i];
for(int j=pre[x];j;j=nex[j]){
if(!dfn[to[j]]) continue;
find(to[j]);
if(dfn[sdom[val[to[j]]]]<dfn[sdom[x]]) sdom[x]=sdom[val[to[j]]];
}
add(lat,sdom[x],x); bel[x]=fa[x]; x=fa[x];
for(int j=lat[x];j;j=nex[j]){
find(to[j]);
if(sdom[val[to[j]]]==x) idom[to[j]]=x;
else idom[to[j]]=val[to[j]];
}
lat[x]=0;
}
for(int i=2,x;i<=cnt;i++){
x=id[i];
if(idom[x]!=sdom[x]) idom[x]=idom[idom[x]];
}
}
void work(){
for(int i=1;i<=n+2;i++) sdom[i]=bel[i]=val[i]=i;
dfs(s); Tarjan(); tot=0;
for(int i=1;i<=n;i++) if(idom[i]) add(cdy,idom[i],i);
}
void input(){
cin>>n; s=n+1;
for(int i=1,k,x;i<=n;i++){
scanf("%d",&k);
while(k--){
scanf("%d",&x);
if(!x) x=s;
add(head,x,i),add(pre,i,x);
}
}
work();
for(int i=cdy[s];i;i=nex[i]) res++;
cout<<res;
}
}t;
signed main(){
t.input();
return 0;
}