欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【HDU 2586】How far away ?

程序员文章站 2022-03-23 14:00:03
...

1.题目链接。题目大意:在一棵树上,每条边都有一定的边权,求u到v最小的边权和。

2.LCA模板题,找到u和v的最小公共祖先,从这里走是最优的。这里采用的是Tarjan算法离线求LCA。

#include<bits/stdc++.h>
using namespace std;
const int N = 50005;
vector<int> v[N], w[N], query[N], num[N];
int pre[N], dist[N], ans[N];
bool vis[N];
#pragma warning(disable:4996)
void Init(int n)
{
	for (int i = 1; i <= n; i++)
	{
		v[i].clear();
		w[i].clear();
		query[i].clear();
		num[i].clear();
		pre[i] = i;
		dist[i] = 0;
		vis[i] = false;
	}
}

int Find(int x)
{
	if (pre[x] != x)
		pre[x] = Find(pre[x]);
	return pre[x];
}

void join(int x, int y)
{
	x = Find(x);
	y = Find(y);
	if (x != y)pre[y] = x;
}

void Tarjan(int cur, int val)
{
	vis[cur] = true;
	dist[cur] = val;
	int size = v[cur].size();
	for (int i = 0; i < size; i++)
	{
		int tmp = v[cur][i];
		if (vis[tmp]) continue;
		Tarjan(tmp, val + w[cur][i]);
		join(cur, tmp);
	}
	int Size = query[cur].size();
	for (int i = 0; i < Size; i++)
	{
		int tmp = query[cur][i];
		if (!vis[tmp]) continue;
		ans[num[cur][i]] = dist[cur] + dist[tmp] - 2 * dist[Find(tmp)];
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n, Q;
		scanf("%d%d", &n, &Q);
		Init(n);
		for (int i = 1; i < n; i++)
		{
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			v[x].push_back(y);
			w[x].push_back(z);
			v[y].push_back(x);
			w[y].push_back(z);
		}
		for (int i = 0; i < Q; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			query[x].push_back(y);
			query[y].push_back(x);
			num[x].push_back(i);
			num[y].push_back(i);
		}
		Tarjan(1, 0);
		for (int i = 0; i < Q; i++)
			printf("%d\n", ans[i]);
	}
	return 0;
}