题目背景
SOURCE:NOIP2015-SHY
题目描述
给出一棵带有边权的树,问两点之间的距离。
输入格式
第一行两个整数 n 和 m ,分别表示点数和询问数。
接下来 n-1 行,每行三个整数 x,y,z,表示 x 与 y 通过一条权为 z 的边连接。
接下来 m 行,每行两个整数 x,y,代表一组询问。
输出格式
输出 m 行,每行一个整数,对应一组询问的答案。
样例数据
输入
3 3
1 2 1
1 3 2
1 2
1 3
2 3
输出
1
2
3
备注
【数据范围】
对 30% 的输入数据 :
1≤n,m≤1000
对 100% 的输入数据 :
1≤n,m≤100000;1≤z≤10000
分析: LCA模板
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
const int N=100010;
int n,m,tot;
int first[N],nxt[N*2],to[N*2],w[N*2];
int fa[N][25],dep[N],dis[N];
bool visit[N];
void addedge(int x,int y,int z)
{
tot++;
nxt[tot]=first[x];
first[x]=tot;
to[tot]=y;
w[tot]=z;
tot++;
nxt[tot]=first[y];
first[y]=tot;
to[tot]=x;
w[tot]=z;
}
void dfs(int u)
{
for(int p=first[u];p;p=nxt[p])
{
int v=to[p];
if(!visit[v])
{
visit[v]=true;
dep[v]=dep[u]+1;
dis[v]=dis[u]+w[p];
fa[v][0]=u;
for(int i=1;i<=20;++i)
fa[v][i]=fa[fa[v][i-1]][i-1];
dfs(v);
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
int len=dep[x]-dep[y];
for(int i=20;i>=0;i--)
if(len&(1<<i))
x=fa[x][i];
if(x==y)
return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int main()
{
//freopen("LCA.in","r",stdin);
//freopen("LCA.out","w",stdout);
int x,y,z;
n=getint(),m=getint();
for(int i=1;i<n;++i)
{
x=getint(),y=getint(),z=getint();
addedge(x,y,z);
}
dep[1]=0,dis[1]=0;
visit[1]=true;
dfs(1);
while(m--)
{
x=getint(),y=getint();
z=lca(x,y);
cout<<dis[x]+dis[y]-2*dis[z]<<'\n';
}
return 0;
}
本题结。