CF2132F

Solution

首先要求出 $1\rarr n$ 的所有路径必定经过的边,枚举每个路径肯定不行,但是从 $1$ 到 $n$ 一定是从 $1$ 的强连通分量到 $n$ 的强连通分量的边,那么关键边一定就是连接强连通分量的边。
所以我们先缩点,然后再我们建新图时,记得记录新边原来的编号,这样方便找。

for (int i = 1; i <= m; i++) {
        LL x = e[i].first, y = e[i].second;
        if (bel[x] != bel[y]) {
            v[bel[x]].emplace_back(bel[y], i);//记录原来的编号 i
            v[bel[y]].emplace_back(bel[x], i);
        }
    }

接下来用 ${dfs}$ 从包含 $1$ 的强连通分量里面出发到包含 $n$ 的强连通分量,并记录路径,这里记录的就是上面代码里的那个编号。
然后我们就可以跑最短路,这里我们记录两个关键字,第一个是距离 $dis$,第二个是边的编号 $id$。
对于任何关键边的端点,我们都加入优先队列里。
在松弛时,如果 $dis_x=dis_{to}+1$,这里加一是因为我们计算的是一条边两边的端点,而边权为 $1$,我们就比较 $ans_{id_x}$ 和 $ans_{id_{to}}$。这里 $ans$ 是我们记录的答案,$to$ 是当前点,$x$ 是枚举的点。

Code

#include <bits/stdc++.h>
using LL = long long;
using namespace std;
const LL N = 2e5 + 5;
LL n, m, dfn[N], vis[N], low[N], cnt, num, st[N], top, bel[N], res[N], dis[N];
vector<pair<LL, LL>> g[N], v[N];
pair<LL, LL> e[N];
set<LL> path;
void tarjan(LL x, LL fa) {
    dfn[x] = low[x] = ++cnt;
    st[++top] = x;
    vis[x] = 1;
    for (auto [i, id] : g[x]) {
        if (id == fa) continue;
        if (!dfn[i]) {
            tarjan(i, id);
            low[x] = min(low[x], low[i]);
        } else if (vis[i]) {
            low[x] = min(low[x], dfn[i]);
        }
    }
    if (low[x] == dfn[x]) {
        num++;
        LL to;
        do {
            to = st[top--];
            bel[to] = num;
            vis[to] = 0;
        } while (to != x);
    }
}
priority_queue<tuple<LL, LL, LL>, vector<tuple<LL, LL, LL>>, greater<tuple<LL, LL, LL>>> q;
 
void dijkstra() {
    memset(dis, 0x3f, sizeof(dis));
    for (auto x : path) {
        auto [i, j] = e[x];
        if (res[i] == 0) {
            q.emplace(0, x, i);
            res[i] = x;
            dis[i] = 0;
        }
        if (res[j] == 0) {
            q.emplace(0, x, j);
            res[j] = x;
            dis[j] = 0;
        }
    }
    while (!q.empty()) {
        auto [cost, id, to] = q.top(); q.pop();
        if (dis[to] != cost) continue;
        for (auto [x, y] : g[to]) {
            if (dis[x] > dis[to] + 1 || (dis[x] == dis[to] + 1 && res[to] < res[x])) {
                dis[x] = dis[to] + 1;
                res[x] = res[to];
                q.emplace(dis[x], res[x], x);
            }
        }
    }
}
 
bool dfs(LL x, LL fa) {
    if (x == bel[n]) return true;
    for (auto [i, j] : v[x]) {
        if (i == fa) continue;
        if (dfs(i, x)) {
            path.insert(j);
            return true;
        }
    }
    return false;
}
 
void solve() {
    cin >> n >> m;
    cnt = num = top = 0;
    for (int i = 1; i <= n; i++) {
        dfn[i] = vis[i] = low[i] = bel[i] = res[i] = dis[i] = 0;
        g[i].clear();
        v[i].clear();
    }
    path.clear();
    for (int i = 1; i <= m; i++) {
        LL x, y;
        cin >> x >> y;
        e[i] = {x, y};
        g[x].emplace_back(y, i);
        g[y].emplace_back(x, i);
    }
    for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, -1);
    for (int i = 1; i <= m; i++) {
        LL x = e[i].first, y = e[i].second;
        if (bel[x] != bel[y]) {
            v[bel[x]].emplace_back(bel[y], i);
            v[bel[y]].emplace_back(bel[x], i);
        }
    }
    dfs(bel[1], 0);
    dijkstra();
    //cout << path.size() << endl;
    LL Q; cin >> Q;
    while (Q--) {
        LL x; cin >> x;
        cout << (res[x] == 0 ? -1 : res[x]) << ' ';
    }
    cout << endl;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}