洛谷 #3379. 【模板】LCA

4 篇文章 0 订阅

倍增

用\(f[cur][i]\)表示\(cur\)的第\(\ 2^i\)个祖先
\(f[cur][i] = f[f[cur][i-1]][i-1]\)
因为\(\ 2{i-1}+2{i-1}=2^i\)

调试记录

\(f[cur][0] = fa\)
#include <cstdio>
#include <algorithm>
#define maxn 500005
#define logn 25
using namespace std;

struct node{
	int to, nxt;
}e[maxn << 1];
int head[maxn], tot = 0;
void addedge(int u, int v){
	e[++tot].to = v, e[tot].nxt = head[u];
	head[u] = tot;
}
int n, m, root;
int dep[maxn], f[maxn][logn + 5];
void dfs(int cur, int fa){
	dep[cur] = dep[fa] + 1;
	f[cur][0] = fa;
	for (int i = 1; (1 << i) <= dep[cur]; i++)
		f[cur][i] = f[f[cur][i - 1]][i - 1];
	for (int i = head[cur]; i; i = e[i].nxt){
		if (e[i].to != fa) dfs(e[i].to, cur);
	}
}
int LCA(int u, int v){
	if (dep[u] > dep[v]) swap(u, v);
	for (int i = logn; i >= 0; i--)
		if (dep[u] <= dep[v] - (1 << i)) v = f[v][i];
	if (u == v) return u;
	for (int i = logn; i >= 0; i--)
		if (f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
	return f[u][0];
}
int main(){
	scanf("%d%d%d", &n, &m, &root);
	for (int u, v, i = 1; i < n; i++){
		scanf("%d%d", &u, &v);
		addedge(u, v), addedge(v, u);
	}
	dfs(root, 0);
	while (m--){ int u, v;
		scanf("%d%d", &u, &v);
		printf("%d\n", LCA(u, v));
	}
	return 0;
}

Tarjan

题解

#include <cstdio>

#define maxn 500005

using namespace std;

struct node_edge{
	int next, to, LCA;
}e[maxn * 2], q[maxn * 2];

int etot = 0, qtot = 1, efirst[maxn], qfirst[maxn], n, m, root;
int f[maxn];

int GetFather(int x){
	if (f[x] == x) return x;
	else return (f[x] = GetFather(f[x]));
}

void eAddEdge(int x, int y){
	etot++;
	e[etot].to = y;
	e[etot].next = efirst[x];
	efirst[x] = etot;
}

void qAddEdge(int x, int y){
	qtot++;
	q[qtot].to = y;
	q[qtot].next = qfirst[x];
	qfirst[x] = qtot;
}

bool vis[maxn];

void dfs(int x){
	vis[f[x] = x] = true;
	for (int i = efirst[x]; i; i = e[i].next){
		if (!vis[e[i].to]){
			dfs(e[i].to);
			f[e[i].to] = x;
		}
	}
	for (int i = qfirst[x]; i; i = q[i].next){
		if (vis[q[i].to]) q[i^1].LCA = q[i].LCA = GetFather(q[i].to);
	}
}

int main(){
	scanf("%d%d%d", &n, &m, &root);
	
	for (int a, b, i = 1; i < n; i++){
		scanf("%d%d", &a, &b);
		eAddEdge(a, b); eAddEdge(b, a); /*1*/
	}
	
	for (int a, b, i = 1; i <= m; i++){
		scanf("%d%d", &a, &b);
		qAddEdge(a, b); qAddEdge(b, a);
	}
	dfs(root);
	for (int i = 1; i <= m; i++) printf("%d\n", q[i * 2].LCA);
	
	return 0;
} 
//https://www.luogu.org/problemnew/show/P3379
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值