恰好最近做了强联通,用tarjan比较多,所以就上tarjan的模版来做这题。
看到别人用tarjan求LCA,用到low和dfn两个数组,我们要明白,dfn是用来记录某个点的根,low是记录某个点能获取到最高的根是多少。用tarjan求LCA的时候只需要low即可
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 40005;
int head[maxn], to[maxn * 2], nx[maxn * 2], cost[maxn * 2], ppp1;
int shead[maxn], sto[maxn], snx[maxn], slca[maxn], sfront[maxn], ppp2;
int n, m;
int vst[maxn], low[maxn], dis[maxn];
void init()
{
memset(vst, 0, sizeof(vst));
memset(dis, 0, sizeof(dis));
memset(head, -1, sizeof(head));
memset(shead, -1, sizeof(shead));
ppp1 = ppp2 = 0;
}
void add_edge(int u, int v, int val)
{
to[ppp1] = v;
nx[ppp1] = head[u];
cost[ppp1] = val;
head[u] = ppp1++;
}
void s_add_edge(int u,int v)
{
sto[ppp2] = v;
snx[ppp2] = shead[u];
sfront[ppp2] = u;
shead[u] = ppp2++;
}
int Find(int x)
{
if(low[x] == x)
return x;
return low[x] = Find(low[x]);
}
void Union(int x, int y)
{
x = Find(x);
y = Find(y);
if(x != y)
low[y] = x;
}
void tarjan(int u)
{
vst[u] = 1;
low[u] = u;
for(int i = head[u]; ~i; i = nx[i])
{
int v = to[i];
if(!vst[v])
{
dis[v] = dis[u] + cost[i];
tarjan(v);
Union(u, v);
}
}
for(int i = shead[u]; ~i; i = snx[i])
{
int v = sto[i];
if(vst[v])
{
int root = Find(v);
slca[i] = slca[i ^ 1] = low[root];
}
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++)
{
int u, v, val;
scanf("%d%d%d", &u, &v, &val);
add_edge(u, v, val);
add_edge(v, u, val);
}
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
s_add_edge(u, v);
s_add_edge(v, u);
}
tarjan(1);
for(int i = 0; i < m; i++)
{
int u = sfront[i * 2];
int v = sto[i * 2];
int root = slca[i * 2];
printf("%d\n", dis[u] - dis[root] + dis[v] - dis[root]);
}
}
return 0;
}