题目:


分析:
这道题真的毒瘤,思想很简单,但是细节很多。。
题意:找到从1~n的必经点(每条信息都能获取),且不在一个点数>=2 的强连通分量中(恰好获取一次)。
先将有向图缩点,转换成一张有向无环图。
然后对缩点后的图进行正反拓扑,求出必经点。
再看必经点是否在一个点数>=2的强联通分量中。
正反拓扑过程:
fs[u]表示从起点到u的路径条数,ft[u]表示从终点到u的路径条数
由乘法原理可知,若一个点满足:fs[u]*ft[u]==fs[t]
这个点是必经点。
细节:
1. 对于存在自环的点,一定不能为最后答案,所以要用self标记一下。
2. 要求用按照遍历顺序输出,要用拓扑序记录一下遍历顺序。
3. 缩点从1出发,而不是将整张图的强联通分量都找出来!!
4. 拓扑的起点为1,终点为n。
5. 缩点后的连边可能会有重边,但这并不影响答案。
6. 路径数会很大,对大质数取模即可(可能会冲突)。

#include<bits/stdc++.h>
using namespace std;
#define ri register int
#define N 1000005
#define ll long long
const ll mod=1e9+7;
int read()
{
int x=0,fl=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*fl;
}
int n,m,tot=0,cnt=0,Ti=0,head[N],nex[N],to[N],fa[N],self[N];
int dfn[N],low[N],stk[N],top=0,bel[N],ru1[N],ru2[N],flag[N],siz[N];
ll fs[N],ft[N];
vector<int> e1[N];
vector<int> e2[N];
vector<int> ans;
vector<int> scc[N];
void init()
{
tot=Ti=cnt=top=0; ans.clear();
for(ri i=1;i<=max(tot,n);++i)
self[i]=siz[i]=dfn[i]=low[i]=stk[i]=bel[i]=ru1[i]=ru2[i]=head[i]=fs[i]=ft[i]=flag[i]=0,e1[i].clear(),e2[i].clear(),scc[i].clear();
}
void add(int a,int b) { if(a==b) { self[a]=true; return ; } to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
void tarjan(int x)
{
dfn[x]=low[x]=++Ti;
if(x==n) siz[x]=1;
stk[++top]=x; flag[x]=true;
for(ri i=head[x];i;i=nex[i]){
int v=to[i];
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(flag[v]) low[x]=min(low[x],dfn[v]);
siz[x]|=siz[v];
}
if(dfn[x] == low[x]){
cnt++;
do{
int xx=stk[top];
scc[cnt].push_back(xx); flag[xx]=false;
bel[xx]=cnt;
}while(stk[top--]!=x);
}
}
queue<int> q;
int tup[N];
void topu()
{
int num=0;
q.push(bel[1]); fs[bel[1]]=1;
while(!q.empty()){
int u=q.front(); q.pop();
tup[++num]=u;
for(ri i=0;i<e1[u].size();++i){
int v=e1[u][i];
fs[v]=fs[v]+fs[u];
if(fs[v]>=mod) fs[v]%=mod;
if(--ru1[v]==0) q.push(v);
}
}
q.push(bel[n]); ft[bel[n]]=1;
while(!q.empty()){
int u=q.front(); q.pop();
for(ri i=0;i<e2[u].size();++i){
int v=e2[u][i];
ft[v]=ft[v]+ft[u];
if(ft[v]>=mod) ft[v]%=mod;
if(--ru2[v]==0) q.push(v);
}
}
for(ri i=1;i<=num;++i){
int u=tup[i];
if( fs[u]*ft[u]%mod==fs[bel[n]] && scc[u].size()==1 && !self[scc[u][0]]) ans.push_back(scc[u][0]);
}
printf("%d\n",ans.size());
for(ri i=0;i<ans.size();++i) printf("%d ",ans[i]);
printf("\n");
}
int main()
{
freopen("i.in","r",stdin);
freopen("i.out","w",stdout);
int T=read();
while(T--){
init();
n=read(), m=read();
int a,b;
for(ri i=1;i<=m;++i) a=read(),b=read(),add(a,b);
tarjan(1);
for(ri i=1;i<=n;++i)
if(dfn[i] && siz[i])
for(ri j=head[i];j;j=nex[j]){
int v=to[j];
if(bel[i]==bel[v] || !siz[v]) continue;//chong bian
e1[bel[i]].push_back(bel[v]);
ru1[bel[v]]++;
e2[bel[v]].push_back(bel[i]);
ru2[bel[i]]++;
}
topu();
}
}
/*
6
4 3
2 4
1 3
3 2
2 2
1 2
2 1
3 1
2 3
4 4
1 2
2 4
3 4
1 3
6 6
1 3
3 2
2 1
1 4
5 4
4 6
7 9
1 2
2 4
2 3
4 3
3 6
6 3
3 5
6 5
5 7
*/
