题目
思路
一道lca板子题,不会的同学可以先康康 详解最近公共祖先(LCA)-CSDN博客
我们可以发现,商人是从1开始,旅行到第一个城镇,再到第二个,第三个……
那么我们只需要求出1~第一个城镇的距离,第一个城镇到第二个城镇的距离,第二个城镇到第三个城镇的距离……最后再把这些距离加起来就得到了答案。
那么,如何求树上两点之间的距离呢?
比如画一张图:
其中deep表示该点的深度(1号节点深度为1)
假设要求u到v之间的距离
那么我们把u到v之间的路径标出来
我们可以发现u到v之间的最短路径是一定会经过lca(u,v)的。
所以,求u->v之间的距离就转化成了求(u->lca(u,v)之间的距离)+(v->lca(u,v)之间的距离)
那么,u到lca(u,v)之间的距离怎么求呢?
其实就是deep[u] - lca(u,v)!(v同理)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,mx[300001][41],deep[300001],id = 1,ans,a[1000001];
vector<int> vec[300001];
void dfs(int x,int fa)
{
deep[x] = deep[fa] + 1;
mx[x][0] = fa;
for(int i = 0;i < vec[x].size();i++)
if(vec[x][i] != fa)
dfs(vec[x][i],x);
}
int lca(int x,int y)
{
if(deep[x] < deep[y]) swap(x,y);
for(int i = 40;i >= 0;i--)
if(deep[mx[x][i]] >= deep[y])
x = mx[x][i];
if(x == y) return x;
for(int i = 40;i >= 0;i--)
if(mx[x][i] != mx[y][i])
{
x = mx[x][i];
y = mx[y][i];
}
return mx[x][0];
}
signed main()
{
cin>>n;
for(int i = 1;i < n;i++)
{
int u,v;
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs(1,0);
for(int i = 1;i <= 40;i++)
for(int j = 1;j <= n;j++)
mx[j][i] = mx[mx[j][i - 1]][i - 1];
cin>>m;
a[0] = 1;
for(int i = 1;i <= m;i++)
{
cin>>a[i];
ans += deep[a[i]] + deep[a[i - 1]] - deep[lca(a[i],a[i - 1])] * 2;
}
cout<<ans;
return 0;
}
结语
如果这篇博客对您有帮助的话,请点赞支持一下吖!