本题解适合像我这样的不具备思维能力的选手。
首先根据题意,一个点如果符合要求,那它必然在一个点数大于 \(2\) 的强联通分量里,因为如果只有一个点它就哪里都去不了。所以首先先对图进行缩点,顺带记录下每个强连通分量的大小。然后如果一个点它可以走入这个强连通分量里,就也是符合条件的,所以在缩点后的新图上反向建边,遍历一遍看看符合条件的强连通分量可以走到哪些点,最后看哪些被打上标记即可。
\(Code\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int s=0,w=1; char c=getchar();
while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
while(isdigit(c)) s=(s<<3)+(s<<1)+(c^48),c=getchar();
return s*w;
}
namespace LgxTpre
{
static const int MAX = 2000010;
static const int INF = 20070707070707;
int n,m;
int x,y;
struct Graph
{
struct edge
{
int nex,to;
}e[MAX<<1];
int head[MAX],cnt;
inline void add(int x,int y)
{
e[++cnt].nex=head[x];
head[x]=cnt;
e[cnt].to=y;
return;
}
}G1,G2;
int dfn[MAX],low[MAX],tot;
int stk[MAX],top;
int sizcol[MAX],col[MAX],num;
int vis[MAX];
void tarjan(int now)
{
dfn[now]=low[now]=++tot;
stk[++top]=now;
vis[now]=1;
for(int i=G1.head[now];i;i=G1.e[i].nex)
{
int to=G1.e[i].to;
if(!dfn[to])
tarjan(to),
low[now]=min(low[now],low[to]);
else
if(vis[to])
low[now]=min(low[now],dfn[to]);
}
if(low[now]==dfn[now])
{
vis[now]=0;
col[now]=++num;
++sizcol[num];
while(stk[top]!=now) col[stk[top]]=num,++sizcol[num],vis[stk[top]]=0,--top;
--top;
}
return;
}
int deg[MAX],flag[MAX],ans;
inline void dfs(int now)
{
flag[now]=1;
for(int i=G2.head[now];i;i=G2.e[i].nex)
{
int to=G2.e[i].to;
if(!flag[to]) dfs(to);
}
return;
}
inline void lmy_forever()
{
n=read(),m=read();
for(int i=1;i<=m;++i)
x=read(),y=read(),G1.add(x,y);
for(int i=1;i<=n;++i)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;++i)
for(int j=G1.head[i],to;j;j=G1.e[j].nex)
if(col[i]!=col[to=G1.e[j].to])
++deg[i],G2.add(col[to],col[i]);
for(int i=1;i<=num;++i)
if(sizcol[i]>=2)
dfs(i);
for(int i=1;i<=num;++i)
if(flag[i])
ans+=sizcol[i];
cout<<ans;
}
};
signed main()
{
LgxTpre::lmy_forever();
return (0-0);
}
标签:缩点,连通,一个点,int,题解,Walk,ABC245F,分量
From: https://www.cnblogs.com/LittleTwoawa/p/16888933.html