Analysis
传送门:https://codeforces.com/gym/104053/problem/C
容易观察到一个限制:对于连向同一个点 V V V的所有点 U i U_i Ui,其到起点的路径和一定完全相等。
那么建反图并查集缩点后按照拓扑序对每条边赋值后差分就能求得合法的点权。
Code
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 3e5 + 10;
#define yes cout << "Yes\n"
#define no cout << "No\n"
struct UnionFind{
std::vector<int> par, rank, size;
int c;
UnionFind() {}
UnionFind(int n) : par(n + 10), rank(n, 0), size(n, 1), c(n){
for (int i = 0; i <= n + 1; ++i) par[i] = i;
}
int find(int i) { return (par[i] == i ? i : (par[i] = find(par[i]))); }
bool same(int i, int j) { return find(i) == find(j); }
int get_size(int i) { return size[find(i)]; }
int count() { return c; }
void merge(int i, int j){
par[find(i)] = par[find(j)];
}
} uf;
vector<int> g[N], invg[N], newg[N];
void solve(){
int n, m; cin >> n >> m;
for(int i = 1; i <= n; i++) {
g[i].clear(); invg[i].clear(); newg[i].clear();
}
uf = UnionFind(n + 1);
for (int i = 1; i <= m; i++){
int u, v; cin >> u >> v;
g[u].push_back(v);
invg[v].push_back(u);
}
for (int i = 1; i <= n; i++){
if (invg[i].empty()) continue;
int now = invg[i][0];
for (int j = 1; j < invg[i].size(); j++){
int u = uf.find(now), v = uf.find(invg[i][j]);
if (u != v) uf.merge(u, v);
}
}
vector<int> in(n + 1, 0), dep(n + 1, 1);
for (int i = 1; i <= n; i++){
for (int v : g[i]){
newg[uf.find(i)].push_back(uf.find(v));
in[uf.find(v)]++;
}
}
queue<int> q;
for (int i = 1; i <= n; i++){
if (i != uf.find(i)) in[i] = -1;
else if (in[i] == 0) q.push(i);
}
while (q.size()){
int now = q.front();
q.pop();
for (int nex : newg[now]){
if (--in[nex] == 0){
q.push(nex);
dep[nex] = dep[now] + 1;
}
}
}
int f = 1;
for (int i = 1; i <= n; i++) if (in[i] > 0) f = 0;
if (f == 0){ no; return; }
yes;
vector<int> ans(n + 1, 1);
for (int i = 2; i < n; i++){
int nex = invg[i][0];
ans[i] = dep[uf.find(i)] - dep[uf.find(nex)];
}
for(int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
}
signed main() {
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 1; cin >> t;
while (t--) solve();
return 0;
}