倍增WA+TLE30分 有注释+码风良好
查看原帖
倍增WA+TLE30分 有注释+码风良好
803885
_8008008楼主2023/12/16 20:22

手搓了好几个树都没问题,难不成是我存图的方式太落后了?

#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;
}
2023/12/16 20:22
加载中...