[CF1045C]Hyperspace Highways
题目大意:给一张$n$个点$m$条边的图,保证若有一个环,一定是完全子图,多次询问两个点之间的最短路径长度
题解:把完全子图缩成一个点,圆方树,方点权值设成$1$,圆点设成$0$即可。
卡点:数组开小
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 100010 #define maxm 500010 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, int b) {return a > b ? a : b;} namespace Tree { int head[maxn << 1], cnt; struct Edge { int to, nxt; } e[maxn << 2]; inline void addE(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } #define M 19 int nodenum, n; int dep[maxn << 1], sum[maxn << 1], fa[M][maxn << 1]; void dfs(int u) { for (int i = 1; i < M; i++) fa[i][u] = fa[i - 1][fa[i - 1][u]]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[0][u]) { fa[0][v] = u; dep[v] = dep[u] + 1; sum[v] = sum[u] + (v > n); dfs(v); } } } inline int LCA(int x, int y) { if (x == y) return x; if (dep[x] < dep[y]) std::swap(x, y); for (int i = dep[x] - dep[y]; i; i &= i - 1) x = fa[__builtin_ctz(i)][x]; if (x == y) return x; for (int i = M - 1; ~i; i--) if (fa[i][x] != fa[i][y]) x = fa[i][x], y = fa[i][y]; return fa[0][x]; } inline int ask(int x, int y) { int lca = LCA(x, y); return sum[x] + sum[y] - (sum[lca] << 1) + (lca > n); } void init(int __n) { n = __n; sum[1] = 0; dfs(1); } #undef M } namespace Graph { int head[maxn], cnt; struct Edge { int to, nxt; } e[maxm << 1]; inline void addE(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } using Tree::nodenum; int DFN[maxn], low[maxn], idx; int S[maxn], top; void tarjan(int u) { DFN[u] = low[u] = ++idx; S[++top] = u; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!DFN[v]) { tarjan(v); low[u] = min(low[u], low[v]); if (low[v] >= DFN[u]) { nodenum++; Tree::addE(nodenum, u); do { v = S[top--]; Tree::addE(nodenum, v); } while (v != e[i].to); } } else low[u] = min(low[u], DFN[v]); } } void init(int n) { tarjan(1); Tree::init(n); } } int n, m, Q; int main() { scanf("%d%d%d", &n, &m, &Q); Tree::nodenum = Tree::n = n; for (int i = 0, a, b; i < m; i++) { scanf("%d%d", &a, &b); Graph::addE(a, b); } Graph::init(n); while (Q --> 0) { int u, v; scanf("%d%d", &u, &v); printf("%d\n", Tree::ask(u, v)); } return 0; }