模板最近的共同祖先

LCA tarjan 离线算法

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 40010;
int first[maxn], head[maxn], cnt, sum;
struct edge
{
	int u, v, w, next;
}e[maxn*2], qe[maxn], Q[maxn];
int ans[maxn];
int f[maxn], vis[maxn];
int d[maxn];
void AddEdge(int u, int v, int w)
{
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = first[u];
	first[u] = cnt++;
	e[cnt].u = v;
	e[cnt].v = u;
	e[cnt].w = w;
	e[cnt].next = first[v];
	first[v] = cnt++;
}

int find(int x)
{
	if(f[x] != x)
		return f[x] = find(f[x]);
	return f[x];
}
void LCA(int u, int k)
{
	f[u] = u;
	d[u] = k;
	vis[u] = true;
	for(int i = first[u]; i != -1; i = e[i].next)
	{
		int v = e[i].v;
		if(vis[v])
			continue;
		LCA(v, k + e[i].w);
		f[v] = u;
	}
	for(int i = head[u]; i != -1; i = qe[i].next)
	{
		int v = qe[i].v;
		if(vis[v])
		{
			ans[qe[i].w] = find(v);
		}
	}
} 

LCA 转RMQ的在线算法

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200010;
struct edge
{
	int u, v, w, next;
}edges[maxn*2], e[maxn];

int E[maxn*2], H[maxn*2], I[maxn*2], L[maxn], R[maxn];
int dp[maxn*2][40];
int cnt, clock, dfn;
int first[maxn];
int a[maxn<<2];
int b[maxn];
int add[maxn<<2];
int degree[maxn];
int vis[maxn];
void AddEdge(int u, int v, int w)
{
	edges[cnt].u = u;
	edges[cnt].v = v;
	edges[cnt].w = w;
	edges[cnt].next = first[u];
	first[u] = cnt++;
	edges[cnt].u = v;
	edges[cnt].v = u;
	edges[cnt].w = w;
	edges[cnt].next = first[v];
	first[v] = cnt++;
}
void dfs(int u, int fa, int dep)
{
	E[++clock] = u;
	H[clock] = dep;
	I[u] = clock;
	L[u] = ++dfn;
	b[dfn] = u;
	for(int i = first[u]; i != -1; i = edges[i].next)
	{
		int v = edges[i].v;
		if(v == fa)
			continue;
		if(vis[v])
			continue;
		vis[v] = true;
		dfs(v, u, dep+1);
		E[++clock] = u;
		H[clock] = dep;
	}
	R[u] = dfn;
}

void RMQ_init(int n)
{
	for(int i = 1; i <= n; i++)
		dp[i][0] = i;
	for(int j = 1; (1<<j) <= n; j++)
		for(int i = 1; i+(1<<j)-1 <= n; i++)
		{
			if(H[dp[i][j-1]] < H[dp[i+(1<<(j-1))][j-1]])
				dp[i][j] = dp[i][j-1];
			else
				dp[i][j] = dp[i+(1<<(j-1))][j-1];
		}
}
int RMQ(int l, int r)
{
	l = I[l], r = I[r];
	if(l > r)
		swap(l, r);
	int len = r-l+1, k = 0;
	while((1<<k) <= len)
		k++;
	k--;
	if(H[dp[l][k]] < H[dp[r-(1<<k)+1][k]])
		return E[dp[l][k]];
	else
		return E[dp[r-(1<<k)+1][k]];
}

LCA倍增法

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 20010;
const int INF = 999999999;
int anc[maxn][16], maxcost[maxn][16];
int fa[maxn], L[maxn], cost[maxn], vis[maxn];
int n, m;
int first[maxn], cnt;
struct edge
{
	int u, v, next;
}e[maxn*2];

void AddEdge(int u, int v)
{
	e[cnt].v = v;
	e[cnt].next = first[u];
	first[u] = cnt++;
	e[cnt].v = u;
	e[cnt].next = first[v];
	first[v] = cnt++;
}

void pre()
{
	for(int i = 1; i <= n; i++)
	{
		anc[i][0] = fa[i]; maxcost[i][0] = cost[i];
		for(int j = 1; (1<<j) < n; j++)
			anc[i][j] = -1;
	}
	for(int j = 1; (1<<j) < n; j++)
		for(int i = 1; i <= n; i++)
			if(anc[i][j-1] != -1)
			{
				int a = anc[i][j-1];
				anc[i][j] = anc[a][j-1];
				maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]);
			}

}

int query(int p, int q)
{
	int tmp, log, i;
	if(L[p] < L[q])
		swap(p, q);
	for(log = 1; (1<<log) <= L[p]; log++);
	log--;

	int ans = -INF;
	for(int i = log; i >= 0; i--)
		if(L[p] - (1<<i) >= L[q])
		{
			ans = max(ans, maxcost[p][i]);
			p = anc[p][i];
		}
	if(p == q)
		return ans;
	for(int i = log; i >= 0; i--)
	{
		if(anc[p][i] != -1 && anc[p][i] != anc[q][i])
		{
			ans = max(ans, maxcost[p][i]);
			ans = max(ans, maxcost[q][i]);
			p = anc[p][i];
			q = anc[q][i];
		}
	}
	ans = max(ans, cost[p]);
	ans = max(ans, cost[q]);
	return ans;
}
void dfs(int u)
{
	for(int i = first[u]; i != -1; i = e2[i].next)
	{
		int v = e[i].v;
		if(vis[v])
			continue;
		vis[v] = 1;
		fa[v] = u;
		L[v] = L[u]+1;
		dfs(v);
	}
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

时间: 2024-09-28 16:04:31

模板最近的共同祖先的相关文章

洛谷P3379 【模板】最近公共祖先(LCA)

P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有倍- 题面这个地方写错了 无论是用RMQ+dfs还是tarjan- 为什么我的倍增超时了 求助!为什么只有70分 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接

【原创】洛谷 LUOGU P3379 【模板】最近公共祖先(LCA) -&gt; 倍增

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

洛谷 P3379 【模板】最近公共祖先(LCA) 如题

P3379 [模板]最近公共祖先(LCA) 时空限制1s / 512MB 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询

luogo p3379 【模板】最近公共祖先(LCA)

[模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表(静态)表示; lca 的倍增算法 //优化 log[] const int maxn=500010; int N,M,S;//S根节点标号 int head[maxn];//head[i]=k 以i为起点的第一条边是edge[k] int dep[maxn],dp[maxn][21];//dp[i][j]

P3379 【模板】最近公共祖先(LCA)(dfs序)

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

P3379 【模板】最近公共祖先(LCA)(欧拉序+rmq)

P3379 [模板]最近公共祖先(LCA) 用欧拉序$+rmq$维护的$lca$可以做到$O(nlogn)$预处理,$O(1)$查询 从这里剻个图 #include<iostream> #include<cstdio> #include<vector> using namespace std; int read(){ char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while('0'&l

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

P3379 【模板】最近公共祖先(LCA)(倍增LCA)

题目链接:https://www.luogu.org/problem/P3379 题目大意: 给一棵以s为根的无向树,回答m个询问,回答出a和b最近的公共祖先. 解题报告: 倍增LCA的模板题,用一个数组 f [i] [j]表示i结点的第$2^{j}$个祖先.显然,一个点的祖先是f[i][0],对于当前点的第$2^{j}$个祖先的第$2^{j}$个祖先,等于当前点的第$2^{j+1}$个祖先,因为$2^{j}+2^{j}=2^{j+1}$.所以有递推式$f[i][j]=f[f[i][j-1]][

P3379 【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

洛谷 P3379 【模板】最近公共祖先(LCA) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=3379 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询