传送门
题意:
给你一张nnn个点mmm条边的图,让你对每个点确定一个编号,规则如下:
(1)(1)(1) 对于不能到的点编号为000。
(2)(2)(2) 对于只有一条路径能到这个点的点编号为111。
(3)(3)(3) 对于有不止一条路径能到这个点的点编号为222。
(4)(4)(4) 对于有无数条路径能到这个点的点编号为333。
思路:
考虑一次dfsdfsdfs能得到什么东西,我们可以通过一次dfsdfsdfs确定下来不能到达的点,还可以确定只有一条路径的点,但是不能确定所有不止一条路径的点,因为有可能到某个点路径有若干条,这个点能到的点应该也可以有两条路径到达,但是如果只跑一次是确定不下来的,所以我们给这些点打个标记,让后再跑一次dfsdfsdfs,这样就可以确定下来所有0,1,20,1,20,1,2的点了。
考虑−1-1−1的点怎么确定,看到环应该可以想到拓扑排序,所以我们把111号点仍队列里面,让后跑拓扑,不能到的点就是−1-1−1点,因为有环的话会类似一个瓶颈卡住他下面的点以及环上的点,所以不能到的点即为可以经过环到达的点,直接标记为−1-1−1即可。
但是这个题细节很多很多,比如如果一开始111就在环里,我们这个时候全部赋值为−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;
}
/**/