P2002 消息扩散

先缩点,然后统计有几个入度为零的点。

然而有重边和自环。

自环需要判断一下,然而重边也许不需要判断?

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;

int from[500010],to[500010],nex[500010],head[100010];
int dfn[100010],low[100010],scc[100010],enter[100010];
int sccnum,dfsnum,instack[100010];
stack <int> s;

void tarjan(int u)
{
	dfn[u]=low[u]=++dfsnum;
	instack[u]=1;
	s.push(u);
	for(int i=head[u];i;i=nex[i])
	{
		if(!dfn[to[i]])
		{
			tarjan(to[i]);
			low[u]=min(low[u],low[to[i]]);
		}
		else if(instack[to[i]])
			low[u]=min(low[u],dfn[to[i]]);
	}
	if(dfn[u]==low[u])
	{
		int v;
		++sccnum;
		do
		{
			v=s.top();
			s.pop();
			instack[v]=0;
			scc[v]=sccnum;
		}while(u!=v);
	} 
	return ;
}

int main()
{
	ios::sync_with_stdio(false);
	int n,m,x,y,ans=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		from[i]=x;
		to[i]=y;
		nex[i]=head[x];
		head[x]=i;
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1;i<=m;i++)
		if(scc[from[i]]!=scc[to[i]])
			++enter[scc[to[i]]];
	for(int i=1;i<=sccnum;i++)
		if(enter[i]==0)
			++ans;
	cout<<ans;
	return 0;
}
posted @ 2018-07-26 20:39  Coool  阅读(97)  评论(0编辑  收藏  举报