小A的最短路 LCA
小A的最短路
https://ac.nowcoder.com/acm/problem/23482
题目描述:
小A这次来到一个景区去旅游,景区里面有N个景点,景点之间有N-1条路径。小A从当前的一个景点移动到下一个景点需要消耗一点的体力值。但是景区里面有两个景点比较特殊,它们之间是可以直接坐观光缆车通过,不需要消耗体力值。而小A不想走太多的路,所以他希望你能够告诉它,从当前的位置出发到他想要去的那个地方,他最少要消耗的
体力值是多少。
题解:可以理解为LCA的模板题了,因为他N个点只有N-1条边,所以是一棵树,但是这个题有一个比较特别的地方,有两个点之间是不需要花体力就可以到达的,这样的话我们就多了在模板题的基础上,也就是他在这棵树上搭了一个通道,所以只需要每次特判一下是否通过这个通道会更近即可也就是
dis(u,v) dis(u,x)+dis(v,y) dis(u,y)+dis(v,x)
这三者之间的最小值。
/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <queue>
#include <string>
const int maxn = 1e6+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 1e9+7;
using namespace std;
const int maxlog=20;
struct node{
int to,next;
}edge[maxn];
int head[maxn],cnt=1;
int deep[maxn];
int fa[maxn][maxlog+1];
inline void add(int u,int v){
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int root,int father){
//cout<<root<<endl;
fa[root][0]=father;
deep[root]=deep[father]+1;
for(int i=1;(1<<i)<=deep[root];i++){
fa[root][i]=fa[fa[root][i-1]][i-1];
}
for(int i=head[root];i;i=edge[i].next){
if(edge[i].to==father) continue;
dfs(edge[i].to,root);
}
}
int lca(int x,int y){
if(deep[x]>deep[y]) swap(x,y);
for(int i=maxlog;i>=0;i--){
if(fa[y][i]!=-1&&deep[fa[y][i]]>=deep[x]){
y=fa[y][i];
}
}
if(x==y) return x;
for(int i=maxlog;i>=0;i--){
if(fa[x][i]!=-1&&fa[y][i]!=-1&&fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
inline int dis(int u,int v){
return deep[u]+deep[v]-2*deep[lca(u,v)];
}
int main(){
//memset(head,-1,sizeof head);
//memset(fa,-1,sizeof fa);
int n;
cin>>n;
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
int x,y;
cin>>x>>y;
int q;
cin>>q;
while(q--){
int u,v;
scanf("%d%d",&u,&v);
int ans=dis(u,v);
ans=min(ans,dis(u,x)+dis(v,y));
ans=min(ans,dis(u,y)+dis(v,x));
printf("%d\n",ans);
}
return 0;
}
题解 文章被收录于专栏
主要写一些题目的题解
