USACO 2008 OCT gold 牧草

题目描述

N (2 <= N <= 1,000)头奶牛,分别编号为1N。还有N颗牧草分别编号为1N。简单起见,第i头奶牛都盯着第i颗牧草。有几对牧草分别用一些小路连接了起来,总共有N-1条双向的小路,小路i连接了AiBi颗牧草(1 <= Ai <= N; 1 <= Bi <= N),小路的长度为Li (1 <= Li <= 10,000) 保证任意两颗牧草总能通过小路走到,也就是说这些小路构成了一棵树。奶牛是群居性的动物,很喜欢串门。奶牛们会问你Q次问题(1 <= Q <= 1,000),每次询问的内容很简单,就是从p1颗牧草到p2颗牧草最短的距离是多少。(1 <= p1 <= N; 1 <=p2 <= N)

 输入

第一行,两个用空格分隔的整数:NQ 第二行到第N行,第i+1行包含三个用空格分隔的整数Ai,Bi,Li N+1行到第N+Q行,每行包含两个用空格分隔的整数p1,p2

 输出

Q行,每行包含每次询问的最短距离的值。

 样例输入 

42

2 1 2

4 3 2

1 4 3

1 2

3 2

样例输出 

2

7

题解:用LCA求出最近公共祖先,然后子节点不断往上搜即可。

#include <cstdio>
#include <cmath>
#define N 1005
int a[N][N],first[N*2],next[N*2],v[N*2],dep[N*2],f[N][13];
bool vis[N];
int n,q,x,y,z,cnt,answer,sum;
using namespace std;
inline void dfs(int root,int k)
{
	vis[root]=1;
	dep[root]=k;
	for (int i=first[root];i;i=next[i])
	  if (!vis[v[i]])
	  {
	  	f[v[i]][0]=root;
	  	dfs(v[i],k+1);
	  }
}
inline int find(int x,int y)
{
	if (dep[x]<dep[y])
	{
		int t=x;
		x=y;
		y=t;
	}
	for (int i=log2(n);i>=0;i--)
	  if (dep[f[x][i]]>=dep[y]) x=f[x][i];
	if (x==y) return x;
	for (int i=log2(n);i>=0;i--)
	  if (f[x][i]!=f[y][i])
	  {
	  	x=f[x][i];
	  	y=f[y][i];
	  }
	return f[x][0];
}
int main()
{
	scanf("%d%d",&n,&q);
	for (int i=1;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		a[x][y]=z;
		a[y][x]=z;
		next[++cnt]=first[x];
		first[x]=cnt;
		v[cnt]=y;
		next[++cnt]=first[y];
		first[y]=cnt;
		v[cnt]=x;
	}
	dfs(1,1);
	for (int i=1;i<=log2(n);i++)
	  for (int j=1;j<=n;j++)
	    f[j][i]=f[f[j][i-1]][i-1];
	for (int i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		answer=find(x,y);
		int j=x;
		sum=0;
		while (j!=answer)
		{
			sum+=a[j][f[j][0]];
			j=f[j][0];
		}
		j=y;
		while (j!=answer)
		{
			sum+=a[j][f[j][0]];
			j=f[j][0];
		}
		printf("%d\n",sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouhongkai06/article/details/80464692