HDU P2586 How far away ?
题目
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
Source
ECJTU 2009 Spring Contest
题解
倍增LCA(模板题入手……)
tip:
① 先建边(建完边后得是棵树),用DFS遍历一趟,得出各个节点到根节点的路径长,以及其深度
② 关键操作:递推,fa[i][j]=fa[i][fa[i]][i-1]][j-1] (就是i这个点向上找 2j 次父亲节点就等于i这个点向上找 xj−1 次的父亲节点后再找 2j−1 次父亲节点)
③ 查询,首先把深度大的那个点不断的找父亲节点直到深度与另一个点深度一样(这里i得从log(高度差)枚举到0,如果提高以后所在的位置仍大于等于另一个点的深度,那么就提高至fa[x][i],这样可以避免多次的枚举),然后把两个点一起按上面的操作继续做(只不过这里提高后两个点的 位置 不能一样),最后,显然我们所得到任意一个点的父亲节点就是这两个点的原节点的最近公共祖先
(讲完了吧……第一次写LCA,讲的有点小瑕疵的话,欢迎大家指出)
代码
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int test,n,m,tot,ans,delta;
int fa[40005][20],d[40005],lnk[40005],dep[40005];
bool vis[40005];
struct edge
{
int nxt,y,v;
} e[80005];
int readln()
{
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') x=x*10+ch-48,ch=getchar();
return x;
}
void add(int x,int y,int v)
{
tot++;e[tot].nxt=lnk[x];lnk[x]=tot;e[tot].y=y;e[tot].v=v;
}
void dfs(int x)
{
vis[x]=true;
for (int i=lnk[x];i;i=e[i].nxt)
{
int y=e[i].y;
if (!vis[y]) {
dep[y]=dep[x]+1;
d[y]=d[x]+e[i].v;
fa[y][0]=x;
dfs(y);
}
}
}
int main()
{
test=readln();
while (test--)
{
memset(lnk,0,sizeof(lnk));
memset(d,0,sizeof(d));
memset(vis,false,sizeof(vis));
memset(dep,0,sizeof(dep));
tot=0;
n=readln();m=readln();
for (int i=1;i<n;i++)
{
int x=readln(),y=readln(),z=readln();
add(x,y,z);add(y,x,z);
}
dfs(1);
for (int j=1;j<=log2(n);j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
while (m--)
{
int x=readln(),y=readln(),t;
ans=d[x]+d[y];
if (dep[x]<dep[y]) t=x,x=y,y=t;
delta=dep[x]-dep[y];
for (int i=log2(delta);i>=0;i--)
{
if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (dep[x]==dep[y]) break;
}
if (x!=y){
for (int i=log2(dep[x]);i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
x=fa[x][0];
}
ans-=d[x]*2;
printf("%d\n",ans);
}
}
return 0;
}