BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA

来源:互联网 发布:musca linux 编辑:程序博客网 时间:2024/05/30 02:53

题目大意:给出一棵树,在上满找三个点,问那个点到这三个点的距离和最短。


思路:可以证明,这个店必然是这三个点之间两个的LCA,然后枚举就可以了。



CODE:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 1000010#define INF 0x3f3f3f3fusing 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;}


0 0