LCA【bzoj3364】 [Usaco2004 Feb]Distance Queries 距离咨询

Description

奶牛们拒绝跑马拉松,因为她们悠闲的生活无法承受约翰选择的如此长的赛道.因此约翰决心找一条更合理的赛道,他打算咨询你.此题的地图形式与前两题相同.但读入地图之后,会有K个问题.每个问题包括2个整数,就是约翰感兴趣的2个农场的编号,请尽快算出这2个农场间的距离.

Input

第1到I+M行:与前两题相同;

第2+M行:一个整数K(1≤K≤10000).

第3+M到2+M+K行:每行输入2个整数,代表两个农场.

Output

对每个问题,输出单独的一个整数,给出正确的距离.

明显(LCA)问题。

(Dfs)建树之后,对于每个询问,直接求带权(LCA)即可

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#define R register
#define N 100860
using namespace std;
inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}
int n,m,head[N],tot,now,ans,gw[N][21],f[N][21],q;
int depth[N];
struct cod{int u,v,w;}edge[N<<2];
inline void add(int x,int y,int z)
{
	edge[++tot].u=head[x];
	edge[tot].v=y;
	edge[tot].w=z;
	head[x]=tot;
}
void dfs(int u,int fa,int dist)
{
	gw[u][0]=dist;f[u][0]=fa;
	depth[u]=depth[fa]+1;
	for(R int i=1;(1<<i)<=depth[u];i++)
	{
		f[u][i]=f[f[u][i-1]][i-1];
		gw[u][i]=gw[u][i-1]+gw[f[u][i-1]][i-1];
	}
	for(R int i=head[u];i;i=edge[i].u)
	{
		if(edge[i].v==fa)continue;
		dfs(edge[i].v,u,edge[i].w);
	}
}
inline int lca(int x,int y)
{
	int res=0;
	if(depth[x]>depth[y])swap(x,y);
	for(R int i=17;i>=0;i--)
		if(depth[x]+(1<<i)<=depth[y])
			res+=gw[y][i],y=f[y][i];
	if(x==y)return res;
	for(R int i=17;i>=0;i--)
	{
		if(f[y][i]==f[x][i])continue;
		res+=gw[x][i]+gw[y][i];
		y=f[y][i],x=f[x][i];
	}
	return res+gw[y][0]+gw[x][0];
}
int main()
{
	in(n),in(m);
	for(R int i=1,x,y,z;i<=m;i++)
	{
		R char opt;
		in(x),in(y),in(z);cin>>opt;
		add(x,y,z);add(y,x,z);
	}
	dfs(1,0,0);
	in(q);
	for(R int l,r;q;q--)
	{
		in(l),in(r);
		printf("%d
",lca(l,r));
	}
}
原文地址:https://www.cnblogs.com/-guz/p/9773442.html