思路:
声明一下,我这道题并没有AC,只得了九十分,最后一个点会超时,暂时没有找到更好的优化方案。
这道题中所求三个点x, y, z的最短路径手推一下就会发现:
令a = LCA(x, y), b = LCA(y, z), c = LCA(x, z)
则路径长度为deep[x]+deep[y]+deep[z]-deep[c]-deep[a]-deep[b];
若a = b, 则聚会点在c, 若b=c,聚会点在a,若a=c,聚会点在b
#include<cstdio> #include<iostream> #include<vector> #include<cmath> using namespace std; const int maxn = 500010; inline void qread(int &x){ x = 0; register int ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') x = 10 * x + ch - 48, ch = getchar(); } int n, m, rt = 1; vector<int> G[maxn]; vector<int> W[maxn]; int llog[maxn]; int f[maxn][25]; int g[maxn]; inline void init(){ qread(n); qread(m); for(register int i=1; i<n; ++i){ register int x, y; qread(x), qread(y); G[x].push_back(y); G[y].push_back(x); } g[rt] = 1; } void dfs(int x){ register int sz = G[x].size(); for(register int i=0; i < sz; ++i) if(!g[G[x][i]]){ f[G[x][i]][0] = x; g[G[x][i]] = g[x] + 1; dfs(G[x][i]); } } inline void STtree(){ for(register int i=2; i<=n; ++i) llog[i] = llog[i >> 1] + 1; for(register int j = 1; j <= llog[n]; ++j) for(register int i=1; i<=n; ++i) f[i][j] = f[f[i][j-1]][j-1]; } inline int LCA(register int x, register int y){ if(x == y) return x; if(g[x] < g[y]) swap(x, y); while(g[x] > g[y]){ x = f[x][llog[g[x] - g[y]]]; } if(x == y) return x; for(register int j = llog[n]; j>=0; --j) if(f[x][j] != f[y][j]){ x = f[x][j]; y = f[y][j]; } return f[x][0]; } int main(void){ init(); dfs(rt); STtree(); while(m--){ register int x, y, z; qread(x), qread(y), qread(z); int a = LCA(x, y), b = LCA(y, z), c = LCA(x, z); if(a == b) printf("%d %d\n", c, g[x] + g[y] + g[z] - g[c] - (g[a] << 1)); else if(b == c) printf("%d %d\n", a, g[x] + g[y] + g[z] - g[a] - (g[b] << 1)); else printf("%d %d\n", b, g[x] + g[y] + g[z] - g[b] - (g[a] << 1)); } }