题解:P10953 逃不掉的路
做题背景
做这题时机房里惨叫一片,大家不是 WA 就是 RE(其实我也一样)。
知识点
- 最近公共祖先(LCA),建议大家先做一下这道题:P3379 【模板】最近公共祖先(LCA);
- 边双连通分量(edcc),建议大家做一下这道题:P8436 【模板】边双连通分量。
思路
通过画图发现,将原图进行缩点后会变成一棵树,而 u 点到 v 点的必经之路长度(几条路,也就是桥)就是
代码
代码有些丑陋,不喜勿喷。
#include <bits/stdc++.h>
#define N 500005
#define M 20
using namespace std;
//typedef pair<int, int> PII;
int n, m, u, v, q, au[N], av[N], cnt1, EE = 1, cnt, dfn[N], low[N], dep[N], anc[N][M], edcc[N], pre[N];
vector<int> e[N];
//vector<vector<int> > ans;
stack<int> st;
struct node
{
int to, ne;
} a[N];
void add(int u, int v) // 加边函数
{
a[++EE] = (node){v, pre[u]};
pre[u] = EE;
}
void tarjan(int u, int fa) // 缩点
{
dfn[u] = low[u] = ++cnt;
st.push(u);
for (int i = pre[u]; i; i = a[i].ne)
{
int to = a[i].to;
if (!dfn[to])
{
tarjan(to, i);
low[u] = min(low[u], low[to]);
}
else if (i != (fa ^ 1))
low[u] = min(low[u], dfn[to]);
}
if (dfn[u] == low[u])
{
edcc[u] = ++cnt1;
while (st.top() != u)
{
edcc[st.top()] = cnt1;
st.pop();
}
st.pop();
}
}
void dfs(int u, int fa) // lca的初始化
{
dep[u] = dep[fa] + 1;
anc[u][0] = fa;
for (int i = 1; i <= M - 2; i++)
anc[u][i] = anc[anc[u][i - 1]][i - 1];
for (auto uu : e[u])
{
int to = uu;
if (to == fa)
continue;
dfs(to, u);
}
}
//void init()
//{
// for (int j = 1; j <= M - 1; j++)
// for (int i = 1; i <= n; i++)
// anc[i][j] = anc[anc[i][j - 1]][j - 1];
//}
int LCA(int x, int y) // 最近公共祖先(lca)
{
if (dep[x] < dep[y])
swap(x, y);
for (int i = M - 3; ~i; i--)
if (dep[anc[x][i]] >= dep[y])
x = anc[x][i];
if (x == y)
return x;
for (int i = M - 3; i >= 0; i--)
if (anc[x][i] != anc[y][i])
x = anc[x][i], y = anc[y][i];
return anc[x][0];
}
int main()
{
cin >> n >> m;
// init();
for (int i = 1; i <= m; i++)
{
cin >> au[i] >> av[i];
add(au[i], av[i]);
add(av[i], au[i]);
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i, 0);
for (int i = 1; i <= m; i++)
if (edcc[au[i]] != edcc[av[i]])
e[edcc[au[i]]].push_back(edcc[av[i]]), e[edcc[av[i]]].push_back(edcc[au[i]]);
dfs(1, 0);
cin >> q;
while (q--)
{
cin >> u >> v;
u = edcc[u], v = edcc[v];
int lca = LCA(u, v);
cout << dep[u] + dep[v] - (dep[lca] << 1) << endl;
}
return 0;
}
// 2025.1.25 16:12 build on FJQZ5Z
完结散花!