首页 > 其他分享 >【模板】最近公共祖先(LCA)倍增

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

时间:2024-10-16 20:47:20浏览次数:8  
标签:head leq int dep fa 祖先 LCA 倍增 模板

 P3379

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

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

## 题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

## 输入格式

第一行包含三个正整数 $N,M,S$,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来 $N-1$ 行每行包含两个正整数 $x, y$,表示 $x$ 结点和 $y$ 结点之间有一条直接连接的边(数据保证可以构成树)。

接下来 $M$ 行每行包含两个正整数 $a, b$,表示询问 $a$ 结点和 $b$ 结点的最近公共祖先。

## 输出格式

输出包含 $M$ 行,每行包含一个正整数,依次为每一个询问的结果。

## 样例 #1

### 样例输入 #1

```
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
```

### 样例输出 #1

```
4
4
1
4
4
```

## 提示

对于 $30\%$ 的数据,$N\leq 10$,$M\leq 10$。

对于 $70\%$ 的数据,$N\leq 10000$,$M\leq 10000$。

对于 $100\%$ 的数据,$1 \leq N,M\leq 500000$,$1 \leq x, y,a ,b \leq N$,**不保证** $a \neq b$。


样例说明:

该树结构如下:

 ![](https://cdn.luogu.com.cn/upload/pic/2282.png) 

第一次询问:$2, 4$ 的最近公共祖先,故为 $4$。

第二次询问:$3, 2$ 的最近公共祖先,故为 $4$。

第三次询问:$3, 5$ 的最近公共祖先,故为 $1$。

第四次询问:$1, 2$ 的最近公共祖先,故为 $4$。

第五次询问:$4, 5$ 的最近公共祖先,故为 $4$。

故输出依次为 $4, 4, 1, 4, 4$。


2021/10/4 数据更新 @fstqwq:应要求加了两组数据卡掉了暴力跳。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,L=19;
int n,m,s,f[N][20],head[N],k,dep[N],lo[N];
struct ed{
	int to,next;
}e[2*N];
void add(int x,int y){
	e[++k].to=y;
	e[k].next=head[x];
	head[x]=k;
}
void dfs(int x,int fa){
	f[x][0]=fa;
	dep[x]=dep[fa]+1;
	for(int i=1;i<=19;i++)f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i!=0;i=e[i].next){
		int to=e[i].to;
		if(to!=fa)dfs(e[i].to,x);
	}
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y]){
		x=f[x][lo[dep[x]-dep[y]]];//printf("oO%d,%d,%d\n",f[x][lo[dep[x]-dep[y]]],x,y);
	}
	
	if(x==y) return x;
	for(int i=19;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[y][0];
}
int main(){//printf("%d",log(1));
	//memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&s);
	for(int i=2;i<=N;i++){
		lo[i]=lo[i/2]+1;
	}
	for(int i=1;i<n;i++){
	int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs(s,0);
	//for(int i=1;i<=n;i++)printf("%d ",dep[i]);
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));
	}
}
/*
5 5 4
3 1
2 4
5 1
1 4
2 4
4 2
3 4
4 2
4 5
*/

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,L=19;
int n,m,s,fa[N],head[N],k,dep[N],lo[N],ans[N];
bool vis[N];
vector<int> e[N];
vector<pair<int,int> > q[N];
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
void dfs(int x){
	fa[x]=x;
	vis[x]=1;
	for(int i=0;i<e[x].size();i++){
		int to=e[x][i];
		if(!vis[to]){
			dfs(to);
			fa[to]=x;
		}
	}
	for(int i=0;i<q[x].size();i++){
		int c=q[x][i].first,cc=q[x][i].second;
		if(vis[c]){
			ans[cc]=find(c);
		}
	}
}
int main(){//printf("%d",log(1));
	//memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<n;i++){
	int x,y;
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
	}
	
	//for(int i=1;i<=n;i++)printf("%d ",dep[i]);
	
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		q[x].push_back((pair<int,int>){y,i});
		q[y].push_back((pair<int,int>){x,i});
	}
	vis[0]=1;
	dfs(s);
	for(int i=1;i<=m;i++){
		printf("%d\n",ans[i]);
	}
}
/*
5 5 4
3 1
2 4
5 1
1 4
2 4
4 2
3 3
2 2
4 5
*/

标签:head,leq,int,dep,fa,祖先,LCA,倍增,模板
From: https://blog.csdn.net/no_play_no_games/article/details/142963651

相关文章

  • 【朝花夕拾】免费个人网页搭建:免费托管、CDN加速、个人域名、现代化网页模板一网打尽
    现代化网页设计的免费宝藏:GitHubPages+CodePen+Cloudflare+US.KG前言在当今数字化时代,个人和企业越来越重视在线形象的建立。GitHubPages提供了一个免费且便捷的平台,允许用户托管静态网站。然而,GitHubPages默认的域名可能不够个性化,因此,许多用户希望将自定义域名绑定......
  • Obsidian之模板的简单使用
    前言:在使用Obsidian时经常对每次新建的文件输入相同的内容是否有更好的解决方法呢,以下是我使用Obsidian模板的一些经验总结用到的插件Templaterquickaddbanner在开始前确保已经安装了以上的插件首先简单的介绍下Templater的功能自定义指定文件夹的新建文件的模板配合......
  • 公司网站的logo如何修改?ab网站模板怎么修改?
    修改公司网站的Logo备份当前Logo在进行任何更改之前,请确保备份现有的Logo文件,以防需要恢复。准备新Logo确保新Logo符合网站的设计风格和尺寸要求。通常推荐使用矢量图形(如SVG)或高分辨率的PNG文件以保证不同设备上的显示效果。登录网站后台使用管理员账号登录网......
  • 公司网站修改?网站主页修改方案模板?
    目标概述明确修改目的(如提升品牌形象、增加转化率)。设定具体可衡量的目标。现状分析当前主页存在的问题。用户反馈总结。设计方案新主页布局草图。颜色搭配与字体选择。关键元素位置调整(如LOGO、导航栏、CTA按钮)。技术实现采用的技术栈(如HTML5,CSS3,J......
  • 公司网站的首页怎么修改?修改网站模板?
    要修改公司网站的首页或更换模板,通常可以按照以下步骤操作:备份现有网站:在进行任何更改之前,确保备份当前的网站数据和文件,以防更新过程中出现错误。选择新的模板:如果使用的是CMS(内容管理系统)如WordPress、Joomla等,可以通过后台管理界面选择新的模板。对于自定义开发的......
  • 网站后台修改模板?公司网站轮播如何修改?
    网站后台修改模板登录后台:使用管理员账号登录网站后台。导航至模板管理:在后台主界面中找到“模板管理”、“主题设置”或类似的选项。选择模板:从模板列表中选择当前使用的模板或想要切换的新模板。编辑模板:进入模板编辑页面,可以对模板的样式、布局等进行调整。......
  • 网站模板修改地址不详?模板网站不能修改吗?
    网站模板修改地址不详查阅文档查看网站后台提供的帮助文档或指南,通常会有详细的说明介绍如何修改模板。联系客服如果找不到相关信息,可以尝试联系网站的技术支持或客服,询问具体的修改路径和方法。探索后台在后台管理系统中仔细探索,尝试找到与模板相关的设置项,如“......
  • 网站栏目模板修改?网站公司地址修改?
    要进行网站栏目模板修改或公司地址修改,通常涉及前端HTML/CSS以及可能的后端逻辑调整。下面分别介绍这两种情况的处理方法:网站栏目模板修改定位模板文件找到存放网站栏目的模板文件,这通常位于网站的前端目录下,如templates文件夹内。备份原有文件修改前,请先备份原有的模......
  • 网站如何从后台修改?企业网站修改模板?
    要修改一个企业网站的后台或模板,通常可以按照以下步骤进行:登录后台管理系统:访问网站提供的后台管理入口,输入管理员账号和密码登录。选择模板管理功能:在后台管理界面中找到“模板管理”、“主题设置”或类似名称的功能模块。编辑现有模板:如果支持直接编辑现有模板......
  • 网站单页模板修改吗?网站后台如何修改标题?
    网站单页模板修改登录后台管理系统:通常需要通过网站提供的后台管理入口登录,使用管理员账号和密码。进入页面管理:在后台找到“页面管理”或类似名称的选项,这里可以管理网站的所有页面。选择要修改的单页:在页面列表中找到需要修改的单页,点击编辑或修改按钮。修......