tarjan模板+计算出入度
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 1000005
using namespace std;
int dfn[N],low[N],head[N],sk[N],scc[N],cnt,sccnum,index,tp;
//scc[]值相同的,梭点后属于同一个点,sccnum表示缩点后有几个点
//dfn[x]表示x这个点dfs到的时间(深浅)
//low[x]此点及其后代指出去的边能返回的最浅的点的时间戳(dfn)
int incnt,outcnt;
int in[N],out[N];
struct edge{
int next,to,w;
}ed[N];
void add(int u,int v,int w){
ed[cnt].w = w;
ed[cnt].to = v;
ed[cnt].next = head[u];
head[u] = cnt++;
}
void tarjan(int root)//head初始值为-1时,用~i; head 初始值为0时用i
{
dfn[root]=low[root]=++index;
sk[++tp]=root;
int i;
for(i=head[root];~i;i=ed[i].next)
{
int v=ed[i].to;
if(!dfn[v])
{
tarjan(v);
low[root]=min(low[root],low[v]);
}
else if(!scc[v])
{
low[root]=min(low[root],dfn[v]);
}
}
if(low[root]==dfn[root])
{
sccnum++;
for(;;)
{
int x=sk[tp--];
scc[x]=sccnum;
if(x==root)break;
}
}
}
int main(){
int n,m;
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(scc,0,sizeof(scc));
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
sccnum=0;
index=0;
tp=0;
cnt=0;
incnt=0;
outcnt=0;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v,1);
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i);
}
if(sccnum==1)printf("0\n");
else{
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=ed[j].next) {
int v=ed[j].to;
if(scc[v]!=scc[i]){
in[scc[v]]++;
out[scc[i]]++;
}
}
}
for(int i=1;i<=sccnum;i++) {
if(!in[i])
incnt++;
if(!out[i])
outcnt++;
}
printf("%d\n",max(incnt,outcnt));
}
}
return 0;
}