题目大意:给出一棵树,在上满找三个点,问那个点到这三个点的距离和最短。
思路:可以证明,这个店必然是这三个点之间两个的LCA,然后枚举就可以了。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 #define INF 0x3f3f3f3f using namespace std; int points,asks; int head[MAX],total; int next[MAX],aim[MAX]; int deep[MAX],father[MAX][20]; int length[MAX]; inline void Add(int x,int y) { next[++total] = head[x]; aim[total] = y; head[x] = total; } void DFS(int x,int last) { deep[x] = deep[last] + 1; length[x] = length[last] + 1; for(int i = head[x]; i; i = next[i]) { if(aim[i] == last) continue; father[aim[i]][0] = x; DFS(aim[i],x); } } void SparseTable() { for(int j = 1; j < 20; ++j) for(int i = 1; i <= points; ++i) father[i][j] = father[father[i][j - 1]][j - 1]; } inline int GetLCA(int x,int y) { if(deep[x] < deep[y]) swap(x,y); for(int i = 19; ~i; --i) if(deep[father[x][i]] >= deep[y]) x = father[x][i]; if(x == y) return x; for(int i = 19; ~i; --i) if(father[x][i] != father[y][i]) x = father[x][i],y = father[y][i]; return father[x][0]; } inline int GetLength(int x,int y,int lca) { return length[x] + length[y] - (length[lca] << 1); } int main() { cin >> points >> asks; for(int x,y,i = 1; i < points; ++i) { scanf("%d%d",&x,&y); Add(x,y),Add(y,x); } DFS(1,0); SparseTable(); for(int x,y,z,i = 1; i <= asks; ++i) { scanf("%d%d%d",&x,&y,&z); int lca = GetLCA(x,y),ans = INF,p = 0; int temp = GetLength(x,y,lca) + GetLength(z,lca,GetLCA(z,lca)); if(temp < ans) ans = temp,p = lca; lca = GetLCA(y,z); temp = GetLength(y,z,lca) + GetLength(x,lca,GetLCA(x,lca)); if(temp < ans) ans = temp,p = lca; lca = GetLCA(x,z); temp = GetLength(x,z,lca) + GetLength(y,lca,GetLCA(y,lca)); if(temp < ans) ans = temp,p = lca; printf("%d %d\n",p,ans); } return 0; }
BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA
原文地址:http://blog.csdn.net/jiangyuze831/article/details/40743709