题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意:就是给你边和询问,每次询问给出两点,询问两点间距
思路:可以转化为LCA,这样每次计算两点距离则为dis[x] + dis[y] - 2 * dis[z] (z为祖先,dis为到根节点的距离),使用的是离线算法
这题因为对模板不熟,在询问时加了反向询问边,在去重时WA了一回
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int maxn = 100050;
struct node
{
int from;
int to;
int nxt;
int w;
int lca;
} e[maxn], qe[maxn];
int fa[maxn], head[maxn], qhead[maxn];
int vis[maxn], dis[maxn], ans[maxn];
int x[maxn], y[maxn];
int num, qnum;
void init()
{
num = qnum = 0;
memset(head, -1, sizeof(head));
memset(qhead, -1, sizeof(qhead));
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
memset(ans, 0, sizeof(ans));
for(int i = 1; i <= maxn; i++)
fa[i] = i;
}
void add(int u, int v, int w)
{
e[num].from = u;
e[num].to = v;
e[num].w = w;
e[num].nxt = head[u];
head[u] = num++;
e[num].from = v;
e[num].to = u;
e[num].w = w;
e[num].nxt = head[v];
head[v] = num++;
}
void qadd(int u, int v)
{
qe[qnum].from = u;
qe[qnum].to = v;
qe[qnum].nxt = qhead[u];
qhead[u] = qnum++;
}
int find(int x)
{
if(x == fa[x])
return x;
return fa[x] = find(fa[x]);
}
void LCA(int u)
{
vis[u] = 1;
for(int i = head[u]; ~i; i = e[i].nxt)
{
if(!vis[e[i].to])
{
dis[e[i].to] = dis[e[i].from] + e[i].w;
LCA(e[i].to);
fa[e[i].to] = u;
}
}
for(int i = qhead[u]; ~i; i = qe[i].nxt)
{
if(vis[qe[i].to])
{
qe[i].lca = find(qe[i].to);
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
init();
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &x[i], &y[i]);
qadd(x[i], y[i]);
}
LCA(1);
for(int i = 1; i <= m; i++)
{
int u = x[i];
for(int k = qhead[u]; ~k; k = qe[k].nxt)
{
int x = qe[k].from;
int y = qe[k].to;
int z = qe[k].lca;
printf("%d\n", dis[x] + dis[y] - 2 * dis[z]);
}
}
}
return 0;
}