传送门
https://www.luogu.org/problemnew/show/P2341
思路
- 先缩点(tarjan版子)
- 只能有一个强联通分量的出度为0
int dfn[N];
int low[N];
struct node
{int v,nxt;}edge[M];
int head[N],cnt;
void add(int u,int v)
{cnt++;edge[cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;}
int t;//时间戳
bool instack[N];int stack[N],top;//栈以及在不在栈
int cc,belong[N],siz[N];//给每一个点分配强连通分量的编号
void dfs(int now)
{
t++;
dfn[now]=low[now]=t;
stack[++top]=now;
instack[now]=true;
for(int i=head[now];i;i=edge[i].nxt)
{
int v=edge[i].v;
if(!dfn[v])//沿树边走用low更新
{
dfs(v);
low[now]=min(low[now],low[v]);
}
else
{
if(instack[v])//沿非树边走,因为可能无法到达该点的father所以用dfn更新
{
low[now]=min(low[now],dfn[v]);
}
}
}
if(low[now]==dfn[now])//回溯到该强连通分量的定点时,弹栈,归类
{
cc++;
while(stack[top]!=now)
{
siz[cc]++;
belong[stack[top]]=cc;
instack[stack[top]]=false;
top--;
}
siz[cc]++;
belong[now]=cc;
instack[now]=false;
top--;
}
}