没啥好说的。就是一个LCA。
不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v。相等的话不用走。否则就是1次操作。
主要是想写一下倍增的板子。
倍增基于二进制。暴力求LCA算法是while循环一步一步往上走。但其实是不需要的。
因为一个点走到它的任意一个祖先都是确定的步数。都可用表示成二进制数。
$lca_{u,i}$代表从$u$向上走$2^{i}$步到哪一个节点
预处理出来。让$u$,$v$同深度,再向上走$x-1$步就好了($x$代表两$u, v$到它们LCA的深度差)
#include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <string> #include <iostream> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } const int N = 1e5 + 10; struct Edge { int v, next; } edge[N]; int n, m, cnt, head[N], fa[N], degree[N], lca[N][17], dep[N]; bool vis[N]; map<string, int> mp; int tol; inline void init() { memset(head, 0, sizeof(head)); memset(fa, 0, sizeof(fa)); memset(vis, 0, sizeof(vis)); memset(degree, 0, sizeof(degree)); memset(lca, 0, sizeof(lca)); cnt = tol = 0; mp.clear(); } inline void addedge(int u, int v) { edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt; } int index(string s) { if (mp.find(s) != mp.end()) return mp[s]; return mp[s] = ++tol; } void dfs(int u) { vis[u] = 1; lca[u][0] = fa[u]; for (int i = 1; i <= 16; i++) lca[u][i] = lca[lca[u][i-1]][i-1]; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (vis[v]) continue; dep[v] = dep[u] + 1; fa[v] = u; dfs(v); } } int Lca(int u, int v) { if (dep[u] < dep[v]) swap(u, v); for (int i = 16; i >= 0; i--) if (dep[lca[u][i]] >= dep[v]) u = lca[u][i]; if (u == v) return u; for (int i = 16; i >= 0; i--) if (lca[u][i] != lca[v][i]) u = lca[u][i], v = lca[v][i]; return lca[u][0]; } int main() { int T = read(); while (T--) { init(); n = read(); m = read(); for (int i = 0; i < n - 1; i++) { string a, b; cin >> a >> b; int u = index(a), v = index(b); addedge(v, u); degree[u]++; } int root = 0; for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; } fa[root] = root; dfs(root); while (m--) { string a, b; cin >> a >> b; int u = index(a), v = index(b); int r = Lca(u, v); printf("%d\n", dep[u] - dep[r] + (v == r ? 0 : 1)); } } return 0; }
交了之后发现跑了两秒多
然后写了发tarjan的 跑了1秒多 果然 tarjan的时间复杂度还是最优的
#include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <string> #include <iostream> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } const int N = 1e5 + 10; struct Edge { int v, next; } edge[N]; int cnt, head[N]; inline void addedge(int u, int v) { edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt; } struct Qedge { int v, next, num; } qedge[N * 2]; int qcnt, qhead[N]; inline void addqedge(int u, int v, int num) { qedge[++qcnt].v = v; qedge[qcnt].next = qhead[u]; qhead[u] = qcnt; qedge[qcnt].num = num; } int n, m, fa[N], degree[N], dep[N]; int ans[N]; bool vis[N]; map<string, int> mp; int tol; inline void init() { memset(head, 0, sizeof(head)); memset(qhead, 0, sizeof(qhead)); memset(fa, 0, sizeof(fa)); memset(vis, 0, sizeof(vis)); memset(degree, 0, sizeof(degree)); memset(dep, 0, sizeof(dep)); memset(ans, 0, sizeof(ans)); cnt = qcnt = tol = 0; mp.clear(); } int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); } int index(string s) { if (mp.find(s) != mp.end()) return mp[s]; return mp[s] = ++tol; } void dfs(int u) { fa[u] = u; vis[u] = 1; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (vis[v]) continue; dep[v] = dep[u] + 1; dfs(v); fa[v] = u; } for (int i = qhead[u]; i; i = qedge[i].next) { int v = qedge[i].v; if (vis[v]) { ans[qedge[i].num] = getfa(v); } } } int main() { int T = read(); while (T--) { init(); n = read(); m = read(); for (int i = 0; i < n - 1; i++) { string a, b; cin >> a >> b; int u = index(a), v = index(b); addedge(v, u); degree[u]++; } int root = 0; for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; } for (int i = 1; i <= m; i++) { string a, b; cin >> a >> b; int u = index(a), v = index(b); addqedge(u, v, i); addqedge(v, u, i); } dep[root] = 0; dfs(root); for (int i = 1; i <= m; i++) { int u = qedge[2 * i].v, v = qedge[2 * i - 1].v; printf("%d\n", dep[u] - dep[ans[i]] + (ans[i] == v ? 0 : 1)); } } return 0; }