二次联通门 : BZOJ 1787: [Ahoi2008]Meet 紧急集合
/* BZOJ 1787: [Ahoi2008]Meet 紧急集合 LCA 树剖预处理Lca 然后对于要查询的三个点 分别求出三个lca 接下来的事就比较神奇了 手模几组样例后就会发现 三个lca必定会有两个相同 这样的话那个不相同的那个就是所要求的点(自己画画图, 就会非常清楚的明白) 然后分别计算三个点到选出的lca的距离就可以了 */ #include <cstdio> #define Max 500097 inline int abs (int a) { return a > 0 ? a : -a; } inline void swap (int &a, int &b) { int now = a; a = b; b = now; } void read (int &now) { now = 0; register char word = getchar (); while (word < '0' || word > '9') word = getchar (); while (word >= '0' && word <= '9') { now = now * 10 + word - '0'; word = getchar (); } } class Tree_Chain_Lca_Type { private : struct Points { int size; int father; int up_chain_point; int deep; } point[Max]; int Count; struct Edges { int to; int next; } edge[Max << 2]; int Edge_Count; int edge_list[Max]; public : inline void AddEdge (int from, int to) { Edge_Count++; edge[Edge_Count].to = to; edge[Edge_Count].next = edge_list[from]; edge_list[from] = Edge_Count; Edge_Count++; edge[Edge_Count].to = from; edge[Edge_Count].next = edge_list[to]; edge_list[to] = Edge_Count; } void Dfs_1 (int now, int father) { int pos = Count++; point[now].father = father; point[now].deep = point[father].deep + 1; for (int i = edge_list[now]; i; i = edge[i].next) if (edge[i].to != father) Dfs_1 (edge[i].to, now); point[now].size = Count - pos; } void Dfs_2 (int now, int chain) { point[now].up_chain_point = chain; int pos = 0; for (int i = edge_list[now]; i; i = edge[i].next) if (edge[i].to != point[now].father && point[edge[i].to].size > point[pos].size) pos = edge[i].to; if (!pos) return; Dfs_2 (pos, chain); for (int i = edge_list[now]; i; i = edge[i].next) if (edge[i].to != pos && edge[i].to != point[now].father) Dfs_2 (edge[i].to, edge[i].to); } int Get_Lca (int x, int y) { while (point[x].up_chain_point != point[y].up_chain_point) { if (point[point[x].up_chain_point].deep < point[point[y].up_chain_point].deep) swap (x, y); x = point[point[x].up_chain_point].father; } return point[x].deep < point[y].deep ? x : y; } int Get_dis (int x, int y) { int now = Get_Lca (x, y); return point[x].deep + point[y].deep - (point[now].deep << 1); } void Clear () { Dfs_1 (1, 0); Count = 0; Dfs_2 (1, 1); } }; Tree_Chain_Lca_Type Make; int N, M; int main (int argc, char *argv[]) { read (N); read (M); int x, y, z; for (int i = 1; i < N; i++) { read (x); read (y); Make.AddEdge (x, y); } Make.Clear (); int now_1, now_2, now_3; int Answer, now; while (M--) { read (x); read (y); read (z); now_1 = Make.Get_Lca (x, y); now_2 = Make.Get_Lca (x, z); now_3 = Make.Get_Lca (y, z); if (now_1 == now_2) now = now_3; else if (now_1 == now_3) now = now_2; else now = now_1; printf ("%d %d ", now, Make.Get_dis (x, now) + Make.Get_dis (y, now) + Make.Get_dis (z, now)); } return 0; }