[洛谷 P4320] 道路相遇(圆方树) | 错题本

文章目录

题目

[洛谷 P4320] 道路相遇

分析

建出圆方树后,两点路径上的必经点就容易找到了,由于圆方树上圆点和方点交错排列,所以答案就是 d e p u + d e p v 2 d e p LCA { u , v } 2 + 1 \dfrac{dep_u + dep_v - 2 \cdot dep_{\text{LCA}\{u, v\}}}{2} + 1

错因

  • 最开始还维护了倍增路径上的圆点数量,很麻烦……

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/C20190102/article/details/107522398
今日推荐