【Usaco Oct08 Gold】奶牛串门(Pasture Walking)(LCA)

0 篇文章 0 订阅
</pre><p align="center" style="font-family: Simsun;font-size:14px;"><span style="font-size:24px;color:blue;">【Usaco Oct08 Gold】奶牛串门(Pasture Walking)</span></p><p align="center" style="font-family: Simsun;font-size:14px;">Time Limit:30000MS  Memory Limit:65536KTotal Submit:76 Accepted:50 <span style="color:read;">Case Time Limit:3000MS</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Description</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">有N (2 <= N <= 1,000)头奶牛,分别编号为1到N。还有N颗牧草分别编号为1到N。简单起见,第i头奶牛都盯着第i颗牧草。 有几对牧草分别用一些小路连接了起来,总共有N-1条双向的小路,小路i连接了Ai及Bi颗牧草(1 <= Ai <= N; 1 <= Bi <= N),小路的长度为Li (1 <= Li <= 10,000)保证任意两颗牧草总能通过小路走到,也就是说这些小路构成了一棵树。 奶牛是群居性的动物,很喜欢串门。奶牛们会问你Q次问题(1 <= Q <= 1,000),每次询问的内容很简单,就是从p1颗牧草到p2颗牧草最短的距离是多少。(1 <= p1 <= N; 1 <=p2 <= N)</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Input</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">第一行,两个用空格分隔的整数:N和Q 第二行到第N行,第i+1行包含三个用空格分隔的整数Ai,Bi,Li 第N+1行到第N+Q行,每行包含两个用空格分隔的整数p1,p2</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Output</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;">共Q行,每行包含每次询问的最短距离的值。</span></p><p align="left" style="font-family: Simsun;font-size:14px;"><strong><span style="font-size:24px;color:#333399;">Sample Input</span></strong></p><p style="font-family: Simsun;font-size:14px;"><span style="font-family:Times New Roman;font-size:14px;"></span></p><pre><span style="font-family:Times New Roman;font-size:14px;">4 2
2 1 2
4 3 2
1 4 3
1 2
3 2</span>

Sample Output

2
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#define maxn 1005
using namespace std;
int fa[maxn][15],dep[maxn],g[maxn][maxn];
int n,m,next[maxn],last[maxn],end[maxn];
void dfs(int x)
{
	int i,t,k;
	dep[x]=dep[fa[x][0]]+1;
	k=ceil(log(dep[x])/log(2));
	for(i=1;i<=k;i++)
	{
		fa[x][i]=fa[fa[x][i-1]][i-1];
		g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1];
//		printf("_%d_\n",g[x][i]);
	}
//	t=last[x];
	while(t)
	{
		dfs(end[t]);
		t=next[t];
	}
	return;
}
int LCA(int x,int y)
{
	int i,s,k,dis=0;
	s=ceil(log(n)/log(2));
	if(dep[x]<dep[y])swap(x,y);
	k=dep[x]-dep[y];
	for(i=0;i<=s;i++)
		if(k&(1<<i))dis+=g[x][i],x=fa[x][i];
		
//		printf("--%d--\n",dis);
		
	if(x==y)return dis;
	s=ceil(log(dep[x])/log(2));
	for(i=s;i>=0;i--)
		if(fa[x][i]!=fa[y][i])
		{
			dis+=g[x][i];x=fa[x][i];
			dis+=g[y][i];y=fa[y][i];
		}
	return dis+=g[x][0]+g[y][0];
}
int main()
{
	int i,j,x,y,z;
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		g[x][0]=z;
		fa[x][0]=y;
		end[i]=x;next[i]=last[y];last[y]=i;//反过来写!!!;
		//ps:dfs()往下搜,g[][]向上找;
		//这题还可以开双边,随便找一点做源点建树; 
	}
	for(i=1;i<=n;i++)
		if(!fa[i][0]){dfs(i);break;}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",LCA(x,y));
	}
	return 0;
}

7

Hint

样例解释: 
询问1:1->2 总代价为2 
询问2:3->4->1->2 总代价为7

Source

Usaco October 2008 Gold

——————直接代码——————
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值