题意:
给你一张 n n n个点 m m m条边的图,让你对每个点确定一个编号,规则如下:
( 1 ) (1) (1) 对于不能到的点编号为 0 0 0。
( 2 ) (2) (2) 对于只有一条路径能到这个点的点编号为 1 1 1。
( 3 ) (3) (3) 对于有不止一条路径能到这个点的点编号为 2 2 2。
( 4 ) (4) (4) 对于有无数条路径能到这个点的点编号为 3 3 3。
思路:
考虑一次 d f s dfs dfs能得到什么东西,我们可以通过一次 d f s dfs dfs确定下来不能到达的点,还可以确定只有一条路径的点,但是不能确定所有不止一条路径的点,因为有可能到某个点路径有若干条,这个点能到的点应该也可以有两条路径到达,但是如果只跑一次是确定不下来的,所以我们给这些点打个标记,让后再跑一次 d f s dfs dfs,这样就可以确定下来所有 0 , 1 , 2 0,1,2 0,1,2的点了。
考虑 − 1 -1 −1的点怎么确定,看到环应该可以想到拓扑排序,所以我们把 1 1 1号点仍队列里面,让后跑拓扑,不能到的点就是 − 1 -1 −1点,因为有环的话会类似一个瓶颈卡住他下面的点以及环上的点,所以不能到的点即为可以经过环到达的点,直接标记为 − 1 -1 −1即可。
但是这个题细节很多很多,比如如果一开始 1 1 1就在环里,我们这个时候全部赋值为 − 1 -1 −1即可,需要特判一下。还有需要将不能经过的点能到达的点的度数减去,因为如果不去掉,拓扑排序这些点就会被认为是环能经过的点,是不合理的。
// Problem: G. How Many Paths?
// Contest: Codeforces - Codeforces Round #731 (Div. 3)
// URL: https://codeforces.com/contest/1547/problem/G
// Memory Limit: 512 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
vector<int>v[N];
int id[N],st[N],d[N];
void dfs1(int u) {
id[u]=1; st[u]=1;
for(auto x:v[u]) {
if(st[x]) {
id[x]=2;
continue;
}
dfs1(x);
}
}
void dfs2(int u,int now) {
st[u]=1;
if(id[u]==2) now=2;
id[u]=now;
for(auto x:v[u]) {
if(st[x]) continue;
dfs2(x,now);
}
}
void topsort() {
if(id[1]==2) {
for(int i=1;i<=n;i++) if(id[i]) id[i]=-1;
return;
}
queue<int>q;
for(int i=1;i<=n;i++) st[i]=0;
q.push(1);
while(q.size()) {
int u=q.front(); q.pop();
st[u]=1;
for(auto x:v[u]) {
if(--d[x]==0) q.push(x);
}
}
for(int i=1;i<=n;i++) if(!st[i]&&id[i]) id[i]=-1;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
int _; scanf("%d",&_);
while(_--) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) id[i]=st[i]=d[i]=0,v[i].clear();
for(int i=1;i<=m;i++) {
int a,b; scanf("%d%d",&a,&b);
d[b]++; v[a].pb(b);
}
dfs1(1);
for(int i=1;i<=n;i++) if(!st[i]) {
for(auto x:v[i]) d[x]--;
}
for(int i=1;i<=n;i++) st[i]=0;
dfs2(1,1);
topsort();
for(int i=1;i<=n;i++) printf("%d ",id[i]);
puts("");
}
return 0;
}
/*
*/