题目
分析
建出圆方树后,两点路径上的必经点就容易找到了,由于圆方树上圆点和方点交错排列,所以答案就是 。
错因
- 最开始还维护了倍增路径上的圆点数量,很麻烦……
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
const int LOG = 20;
const int MAXN = 500000;
const int MAXM = 1000000;
int N, M;
std::vector<int> G[MAXN + 5];
int SqrCnt;
std::vector<int> T[MAXN * 2 + 5];
int Dep[MAXN * 2 + 5];
int Anc[MAXN * 2 + 5][LOG + 5];
void AddEdge(int u, int v) {
T[u].push_back(v), T[v].push_back(u);
}
void Dfs(int u, int fa, int dep) {
Dep[u] = dep, Anc[u][0] = fa;
for (int i = 0; i < int(T[u].size()); i++) {
int v = T[u][i];
if (v != fa)
Dfs(v, u, dep + 1);
}
}
std::stack<int> S;
int Dfn[MAXN + 5], Low[MAXN + 5], DfnCnt;
void Dfs(int u, int fa) {
S.push(u);
Dfn[u] = Low[u] = ++DfnCnt;
for (int i = 0; i < int(G[u].size()); i++) {
int v = G[u][i];
if (v == fa)
continue;
if (!Dfn[v]) {
Dfs(v, u);
Low[u] = std::min(Low[u], Low[v]);
if (Low[v] >= Dfn[u]) {
AddEdge(u, ++SqrCnt);
while (!S.empty()) {
int x = S.top(); S.pop();
AddEdge(x, SqrCnt);
if (x == v)
break;
}
}
}
else
Low[u] = std::min(Low[u], Dfn[v]);
}
}
int GetLCA(int u, int v) {
if (Dep[u] < Dep[v]) std::swap(u, v);
int k = Dep[u] - Dep[v];
for (int i = 0; i <= LOG; i++)
if ((k >> i) & 1)
u = Anc[u][i];
if (u == v) return u;
for (int i = LOG; i >= 0; i--)
if (Anc[u][i] != Anc[v][i])
u = Anc[u][i], v = Anc[v][i];
return Anc[u][0];
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= M; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v), G[v].push_back(u);
}
SqrCnt = N;
Dfs(1, 0);
Dfs(1, 0, 0);
for (int j = 1; j <= LOG; j++)
for (int i = 1; i <= SqrCnt; i++)
Anc[i][j] = Anc[Anc[i][j - 1]][j - 1];
int Q; scanf("%d", &Q);
while (Q--) {
int u, v;
scanf("%d%d", &u, &v);
int LCA = GetLCA(u, v);
printf("%d\n", (Dep[u] + Dep[v] - 2 * Dep[LCA]) / 2 + 1);
}
return 0;
}