手搓了好几个树都没问题,难不成是我存图的方式太落后了?
#include<iostream>
#include<vector>
#include<math.h>
#include<cmath>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
double _log(int x,int y){
return log(y)/log(x);
}
const int maxn=500001;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-')f=-1;ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n=read(),m=read(),s=read();
vector<int>map[maxn];//存树用的
int Lv[maxn];//深度
int fa[maxn][20];//fa[i][j]=i的2^j级祖先
void bfs(){
for(int i=0;i<maxn;i++){
for(int j=0;j<20;j++){
fa[i][j]=-1;
}
Lv[i]=-1;
}
//初始化
queue<int>b;
bool vis[maxn];
memset(vis,0,sizeof(vis));
b.push(s);
int level=0;
while(!b.empty()){
int len=b.size();
level++;//深度
while(len--){
if(vis[b.front()]){
b.pop();
continue;
}
Lv[b.front()]=level;
vector<int>son=map[b.front()];
for(int i=0;i<son.size();i++){
if(vis[son[i]])continue;//防止把父亲看成儿子
fa[son[i]][0]=b.front();
b.push(son[i]);
}
vis[b.front()]=true;//打标记
b.pop();
}
}
b.push(s);
memset(vis,0,sizeof(vis));
while(!b.empty()){
if(vis[b.front()]){
b.pop();
continue;
}
vector<int>son=map[b.front()];
for(int i=0;i<son.size();i++){
if(vis[son[i]])continue;
b.push(son[i]);
}
vis[b.front()]=true;
for(int i=1;;i++){
//下面3个都是没有2^i级祖先的
if(i-1<0){
fa[b.front()][i]=-1;
break;
}
else if(fa[b.front()][i-1]<0){
fa[b.front()][i]=-1;
break;
}
else if(fa[fa[b.front()][i-1]][i-1]<0){
fa[b.front()][i]=-1;
break;
}
//b.f的2的i次方级祖先=b.f的2的i-1次方及祖先的2的i-1次方级祖先
else fa[b.front()][i]=fa[fa[b.front()][i-1]][i-1];
}
b.pop();
}
}
int lca(int x,int y){
if(Lv[x]<Lv[y])swap(x,y);
bool vis[maxn];
memset(vis,0,sizeof(vis));
if(Lv[x]>Lv[y])
//跳到同一个深度
while(true){
bool flag=false;
for(int i=(int)_log(2,Lv[x]);;i--){
int to=fa[x][i];
if(to<0)continue;
if(vis[to])continue;//访问过了
vis[x]=true;//标记
if(Lv[to]>Lv[y]){//成功完成跳跃
x=to;
break;
}
if(Lv[to]==Lv[y]){
x=to;
flag=true;//倍增完成
break;
}
}
if(flag)break;
}
if(x==y)return x;
int ans=x;
while(true){
bool flag=false;
for(int i=(int)_log(2,Lv[x]);;i--){
if(i<0){//2^i级祖先全部重合
flag=true;
break;
}
int xto=fa[x][i],yto=fa[y][i];
if(xto<0||yto<0)continue;
if(xto!=yto){
x=xto,y=yto;//不重合就跳
break;
}else{
ans=xto;//更新答案
}
}
if(flag=true)break;
}
return ans;
}
int main(){
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
map[x].push_back(y);
map[y].push_back(x);
}
bfs();
while(m--){
int x=read(),y=read();
printf("%d\n",lca(x,y));
}
return 0;
}