倍增TLE30分求调
查看原帖
倍增TLE30分求调
1168486
DomiSun楼主2025/7/19 01:53

其实就是把x和y提到同一高度这一步骤我改了改,但我认为没有问题

假设x < y,我们用一个变量存一下x和y的深度之差

d = dep[y] - dep[x];

所以x要跳到它的第d个祖先,然后我们把d转为二进制

发现我们可以通过二进制表示出它的二次幂相加,例如

d = 27 -> 11011(二进制) -> 16 + 8 + 2 + 1 不难发现它的路径是确定的

我们只需要判断二进制每一位是否为1,为1的话就跳到第 2 ^ (二进制位数) 个祖先,这样从小到大跳和从大到小跳难道不一样吗?

本蒟蒻不明白为什么,求巨佬帮忙解惑

#include <bits/stdc++.h>
using namespace std;
vector <int> g[500100];
int n,m,s;
int f[500010][100],dep[500010];
void dfs(int u,int fa){
	f[u][0] = fa;
	dep[u] = dep[fa] + 1;
	for(auto v : g[u]){
		if(v == fa) continue;
		dfs(v,u);
	}
}
void init(){
	for(int j = 1;(1 << j) <= n;j++){
		for(int i = 1;i <= n;i++){
			f[i][j] = f[f[i][j-1]][j-1];
		}
	}
}
int lca(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	int d = dep[u] - dep[v];
	for(int i = 0;i <= __lg(d);i++){//看这一行,我把循环反过来写了
		if(d >> i & 1){//位运算,二进制第i位的数
			u = f[u][i];
		}
	}
	if(u == v) return u;
	for(int i = 21;i >= 0;i--){
		if(f[u][i] != f[v][i]){
			u = f[u][i],v = f[v][i];
		}
	}
	return f[u][0];
}
int main(){
	cin >> n >> m >> s;
	for(int i = 1,u,v;i < n;i++){
		cin >> u >> v;
		g[u].emplace_back(v);
		g[v].emplace_back(u);
	}
	dfs(s,0);
	init();
	while(m--){
		int u,v;
		cin >> u >> v;
		cout << lca(u,v) << "\n";
	}
	return 0;
}
2025/7/19 01:53
加载中...