首页 > 代码库 > BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA
BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA
题目大意:给出一棵树,在上满找三个点,问那个点到这三个点的距离和最短。
思路:可以证明,这个店必然是这三个点之间两个的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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。