[AHOI2008]MEET 紧急集合
模板题,容易得到集合点一定在之间。
所以我们只要求出三者的然后求一个总距离最小值去更新答案即可。
树链剖分求也算是倍增吧!
/* Author : lifehappy */ #include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int head[N], to[N], nex[N], cnt = 1; int fa[N], top[N], son[N], sz[N], dep[N]; int n, m; void add(int x, int y) { to[cnt] = y; nex[cnt] = head[x]; head[x] = cnt++; } void dfs1(int rt, int f) { fa[rt] = f, dep[rt] = dep[f] + 1; sz[rt] = 1; for(int i = head[rt]; i; i = nex[i]) { if(to[i] == f) continue; dfs1(to[i], rt); sz[rt] += sz[to[i]]; if(!son[rt] || sz[son[rt]] < sz[to[i]]) son[rt] = to[i]; } } void dfs2(int rt, int tp) { top[rt] = tp; if(!son[rt]) return ; dfs2(son[rt], tp); for(int i = head[rt]; i; i = nex[i]) { if(to[i] == fa[rt] || to[i] == son[rt]) continue; dfs2(to[i], to[i]); } } int lca(int x, int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } int dis(int x, int y) { return dep[x] + dep[y] - 2 * dep[lca(x, y)]; } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); scanf("%d %d", &n, &m); for(int i = 1; i < n; i++) { int x, y; scanf("%d %d", &x, &y); add(x, y); add(y, x); } dfs1(1, 0); dfs2(1, 1); for(int i = 1; i <= m; i++) { int x, y, z, a[3]; scanf("%d %d %d", &x, &y, &z); a[0] = lca(x, y), a[1] = lca(x, z), a[2] = lca(y, z); int ans, res = 0x3f3f3f3f; for(int j = 0; j < 3; j++) { int temp = dis(a[j], x) + dis(a[j], y) + dis(a[j], z); if(temp < res) { res = temp; ans = a[j]; } } printf("%d %d\n", ans, res); } return 0; }