贪心做法,一开始将1号点作为最短路径树的根,然后左边从2开始,右边从n开始,只要之前加入的点有边连向他们就加入
这样一个点加入的时间就是他的dis值,最短路径树上的父亲也可以确定,于是输出时非树边长度为n,树边长度为两个端点dis之差
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N = 100005;
struct edge{
int u, v;
};
vector<int>g[N];
//has[u]标记是否有从访问过的点到点u的边
bool has[N];
//标记访问时间
int dis[N];
edge e[N];
int n, m;
void add(int u, int v, int i){
g[u].push_back(v);
e[i].u = u;
e[i].v = v;
}
void tmp(){
memset(has, false, sizeof has);
memset(dis, 0, sizeof dis);
dis[1] = 0;
for (int i = 0; i < g[1].size(); i++){
int v = g[1][i];
has[v] = true;
}
int cnt = 1, l = 2, r = n;
while (l <= r){
if (l == r)r = 0;
if (has[l]){
dis[l] = cnt++;
int u = l;
for (int i = 0; i < g[u].size(); i++){
int v = g[u][i];
has[v] = true;
}
l++;
}
if (has[r]){
dis[r] = cnt++;
int u = r;
for (int i = 0; i < g[u].size(); i++){
int v = g[u][i];
has[v] = true;
}
r--;
}
}
}
int main(){
//freopen("in.txt", "r", stdin);
int t; scanf("%d", &t);
while (t--){
scanf("%d %d", &n, &m);
for (int i = 0; i <= n; i++)g[i].clear();
for (int i = 1; i <= m; i++){
int u, v; scanf("%d %d", &u, &v);
add(u, v, i);
}
tmp();
for (int i = 1; i <= m; i++){
int u = e[i].u, v = e[i].v;
if (dis[u] < dis[v])printf("%d\n", dis[v] - dis[u]);
else printf("%d\n", n);
}
}
return 0;
}