题目描述
https://vjudge.net/problem/HDU-2586
比较容易看懂就不说了。
思路分析
tarjan第一题,没什么太多要分析的
关注点有以下几个:
1、计算方法是将这个无根树化成以节点1为根的有根树,然后dfs出每一个点距离到节点1的距离,然后由几何关系得出答案。
2、我们会先将它的所有查询都存起来进行操作,具体看代码。
3、在union操作的时候,我们需要注意:一定要把子节点合并到父节点,不能像写并查集一样想和哪边和哪边。
完整代码
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 4e4 + 10;
struct Edge {
int to;
int next;
int w;
}e[maxn << 2];//
vector<int> query[maxn];
vector<int> nums[maxn];
int s[maxn] = { 0 };//
int head[maxn] = { 0 };//
int n, m;
int T;
int cnt;//
int vis[maxn];//
int dis[maxn];//
int ans[maxn];
void init() {
cnt = 0;
for (int i = 0; i < maxn; i++) head[i] = -1;
memset(e, 0, sizeof(e));
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= n; i++) {
s[i] = i;
query[i].clear();
nums[i].clear();
}
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
}
void add(int u, int v, int w) {
e[cnt].to = v;
e[cnt].next = head[u];
e[cnt].w = w;
head[u] = cnt++;
}
int find(int x) {
if (s[x] == x) return x;
int t = x;
while (s[t] != t) t = s[t];
while (x != t) {
int tmp = s[x];
s[x] = t;
x = tmp;
}
return t;
}
void Union(int x, int y) {
int root1 = find(x);
int root2 = find(y);
if (root1 == root2) {
return;
}
s[root2] = root1;
}
void tarjan(int u, int val) {
vis[u] = 1;
dis[u] = val;
for (int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].to;
if (vis[v]) continue;
tarjan(v, val + e[i].w);
Union(u, v);
}
for (int i = 0; i < query[u].size(); i++) {
int v = query[u][i];
if (vis[v]) {
int t = s[find(v)];
ans[nums[u][i]] = dis[u] + dis[v] - 2 * dis[find(v)];
}
}
}
int main()
{
cin >> T;
while (T--) {
cin >> n >> m;
init();
for (int i = 1; i < n; i++) {
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
add(y, x, z);
}
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
query[x].push_back(y);
query[y].push_back(x);
nums[x].push_back(i);
nums[y].push_back(i);
}
//cout << "ok" << endl;
tarjan(1, 0);
//cout << "ok" << endl;
for (int i = 0; i < m; i++) {
cout << ans[i] << endl;
}
}
return 0;
}