題目鏈接: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;
}