倍增求 LCA

时间复杂度 :
求出 表, 然后利用 表求出

vi d(N);
vii f(N, vi(20)); //f[x][i] 表示 x 向上跳 2 ^ i 步
 
//建立 ST 表
void dfs(int u, int father){
	d[u] = d[father] + 1; //深度
	f[u][0] = father;
	rep(i, 1, 19)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(auto v : G[u]){
		if(v == father) continue;
		dfs(v, u);
	}
	return;
}
 
//求  u 和 v 的 lca 
int lca(int u, int v){
	if(d[u] < d[v]) swap(u, v); // u 作为深度更深的那一个
	
	per(i, 19, 0)
		if(d[f[u][i]] >= d[v])
			u = f[u][i];
		
	if(u == v) return v; //深度小的那个本省就是它们的 lca 
	
	per(i, 19, 0){
		if(f[u][i] != f[v][i]){
			u = f[u][i];
			v = f[v][i];
		}
	}
	return f[u][0];
}
 
 

例题:

下面的例题是一些题面中并没有明确告诉你去求 ,但是实际上运用到了 并且需要你自己去求的题目

天天爱跑步
题意

哪个天才可以来教我做这道题

思路

记 的深度为 , 的最近公共祖先为 , 出现观察员的时间为

到 的最短路一定是 从 先走到了 , 然后再从 走到 .

对于观察点 来说,有两种情况这个人贡献了价值, 分别为 走到 这段路上, 以及 走到 这段路上.

第一种情况:

是否经过角度的条件: 且
是否达到时间要求的条件 :

引入一个 数组 , 表示深度等于 的数量的,使用 遍历

第二种情况:

是否经过角度的条件: 且
是否达到时间要求的角度 :

Tarjan 求 LCA

树链刨分 求 LCA