//目前会三个版本
//1.倍增法。看挑战。
//2.rmq.看挑战
//3.离线 tarjan看http://www.cnblogs.com/JVxie/p/4854719.html
//离线的基本原理是依据dfs的括号性的(看算法导论找dfs括号性)
//在已知各个询问的时候我们阔以用并查集来辅助。。首先init() 另father[i]=i;然后开始dfs()
//这里还需要一个visit[i]数组,用以记录以i为根的子树是否已经遍历完成。如果有询问(a,b)即询问a与b的公共祖先。那么在dfs时,如果以a为根的树
//遍历完成时此时,刚刚要把visit[a]=1在此之前我们把father[a]修改为dfs时a的父亲节点然后看看visit[b]是否等于1如果visit[b]=1
//那么find(a)函数返回的值就是最近公共祖先(什么是find(a)函数,看挑战程序设计竞赛并查集一张即知)如果visit[b]=0那么等到visit[b]要成为1时
//再对b做相似的操作。
//举例:点1连点2 点1连点3 1为根 询问(2,3)init()然后dfs(1)开始 到点2发现点2没有子节点了此时以2为根的子树遍历完成,准备把visit[2]=1,
//在这之前father[2]=1;然后看visit[3]==1,现在visit[3]=0所以什么都不做然后visit[2]=1,然后回到1.此时1还没遍历完,开始遍历3,发现以3为根的
//子树无子节点。遍历完成,准备visit[3]=1在这之前修改father[3]=1,然后看visit[2]==1(为什么知道是看2点呢?因为询问的是(2,3)嘛。
//如果还有询问(3,4)当然还要看visit[4])此时,visit[2]=1所以find(3);函数返回值1,所以询问(2,3)的值为1.其他都一样。。。。很简单嘛。。
//poj 1470(tarjan)
bzoj 1787
//有坑点。。也许算不上。。主要是我太弱。。。。
//此题如果用深度的绝对值来求距离就会造成错误 比如输入以下数据:
//6 1
//1 2
//2 5
//2 6
//6 3
//6 4
//5 3 4
//正确答案是6 4 然而用绝对值就是6 2就呵呵了
//此题除了上述我犯错外还有标记(1)那个地方写错了i>=0而不是i>0 还有就是把distfa[num][i]写成了distfa[i][num];
//上述3个sb错误让我搞了一下午......
//此题的分析就是注意如果a,b,c中先求(a,b)的lca q和(b,c)的lca p然后如果dist[q]>=dist[q]证明a,b,都能到q 运用这种性质阔以分析出(a,c)的lca要么是p,要么是q或者是比q还深的点分类讨论一下就有网上说的结果了。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct edgee
{
int to;
};
edgee edge[2000050];
int first[1000050], nextt[2000050];
int distfa[1000050][22], dist[1000050];;
int edgetot = 1,m,n;
void addedgee(int from, int to)
{
edge[edgetot].to = to;
nextt[edgetot] = first[from];
first[from] = edgetot;
edgetot++;
edge[edgetot].to = from;
nextt[edgetot] = first[to];
first[to] = edgetot;
edgetot++;
}
void dfs(int num,int fa,int deep)
{
dist[num] = deep; distfa[num][0] = fa;
for (int i = 1; distfa[num][i - 1]; i++){
int a = distfa[distfa[num][i - 1]][i - 1]; int b = distfa[num][i - 1];
distfa[num][i] = distfa[distfa[num][i-1]][i - 1];
}
for (int i = first[num]; i; i = nextt[i])
{
int to = edge[i].to;
if (!dist[to])
dfs(to, num, deep + 1);
}
}
int lca(int a, int b)
{
if (dist[a] > dist[b])swap(a, b);
int len = dist[b] - dist[a];
for (int i = 0; len; len >>= 1, i++)
{
int kind = len % 2;
if (kind == 1)
b = distfa[b][i];
}
int temp = 0;
for (int i = 21; i>=0; i--)//(1)
{
if (distfa[a][i] != distfa[b][i])
a = distfa[a][i], b = distfa[b][i];
}
if (a == b)
temp = a;
else
temp = distfa[a][0];
return temp;
}
int getlenth(int a, int b)
{
int r = lca(a, b);
int k = dist[a] + dist[b] - 2 * dist[r];
return k;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
addedgee(a, b);
}
dfs(1, 0, 1);
for (int i = 0; i < m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int k1 = lca(a, b); int k2 = lca(b, c); int k3 = lca(a, c);
int len,k;
if (k1 == k2)
len = getlenth(a,k3) + getlenth(b , k3) + getlenth(c, k3), k = k3;
else
{
if (k2 == k3)
len = getlenth(a, k1) + getlenth(b, k1) + getlenth(c, k1), k = k1;
else
if (k1 == k3)
len = getlenth(a, k2) + getlenth(b, k2) + getlenth(c, k2), k = k2;
}
printf("%d %d\n", k, len);
}
return 0;
}