首页 > 其他分享 >【学习笔记】最近公共祖先

【学习笔记】最近公共祖先

时间:2024-01-30 17:00:32浏览次数:23  
标签:祖先 fath 笔记 int depth 公共 include 节点

最近公共祖先简称 LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。 ——OI Wiki

我们首先想到的肯定就是暴力往上爬,直到它们相遇。但是这个算法在数据量很大的时候就会超时。因此我们有了倍增优化的 LCA。

倍增是什么呢?顾名思义,就是每次翻倍跳。但是在这里,我们不是从小到大跳,而是从大到小跳。

那么这个算法怎么实现呢?我们先保存每个节点的深度和祖先节点。其中 fath[x][i] 表示节点 \(x\) 的第 \(2^i\) 个祖先,可以用 dfs 预处理出来,from[x] 表示节点 \(x\) 的父节点,depth[x] 表示节点 \(x\) 的深度。

现在我们就我们可以开始求 LCA 了。第一步,我们要将 \(u,v\) 两点跳转到同一深度。计算出 \(u,v\) 的深度之差 \(y\),对 \(y\) 进行二进制的拆分,也就是将 \(y\) 次跳转优化为 \(y\) 的二进制中所含的 \(1\) 的个数次跳转。如果两点相遇则问题解决。第二步,我们从可能的最大步数开始一直进行尝试,不断减半,如果跳到的地方相同就不跳,否则就跳,再一步一步往上调整,直到找到最近公共祖先。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int N=5e5+5;
int fath[N][20],from[N],depth[N],n,m,c,k,x,y,q,u,v,t,ans,root=0;
vector<int> G[N];
void getDepth_dfs(int root){
	for(unsigned i=0;i<G[root].size();i++){
		int next=G[root][i];
		depth[next]=depth[root]+1;
		getDepth_dfs(next);
	}
}
void getParents(){
	for(int up=1;(1<<up)<=n;up++)
		for(int i=1;i<=n;i++)
			fath[i][up]=fath[fath[i][up-1]][up-1];
}
int LCA(int u,int v){
	if(depth[u]<depth[v])
		swap(u,v);
	int i=-1;
	while((1<<(i+1))<=depth[u])
		i++;
    for(int j=i;j>=0;j--)
        if(depth[u]-(1<<j)>=depth[v])
            u=fath[u][j];
    if(u==v) return u;
    for(int j=i;j>=0;j--) {
        if(fath[u][j]!=fath[v][j]) {
            u=fath[u][j];
            v=fath[v][j];
        }
    }
    return fath[u][0];
}
int main(){
	ios::sync_with_stdio(false);
	memset(fath,-1,sizeof(fath));
	memset(from,-1,sizeof(from));
	memset(depth,-1,sizeof(depth));
	cin>>n>>m;
	for(int i=1;i<=n-1;i++){
		cin>>x>>y;
		G[x].push_back(y);
		fath[y][0]=x;
		from[y]=x;
	}
	depth[root]=1;
	getDepth_dfs(root);
	getParents();
	while(m--){
		cin>>x>>y;
		ans=LCA(x,y);
		cout<<ans<<endl;
	}
	return 0;
}

标签:祖先,fath,笔记,int,depth,公共,include,节点
From: https://www.cnblogs.com/Death-Basic/p/17997483/least-common-ancestors

相关文章

  • 1/30 学习进度笔记
    无论Hive还是SparkSQL分析处理数据时,往往需要使用函数,SparkSQL模块本身自带很多实现公共功能的函数,在pyspark.sql.functions中。SparkSQL与Hive一样支持定义函数:UDF和UDAF,尤其是UDF函数在实际项目中使用最为广泛。回顾Hive中自定义函数有三种类型:第一种:UDF(User-Defined-Fun......
  • 美赛2023C练习-做题笔记
    代码:clc;TC=ProblemCDataWordle;%数据处理noC=TC(:,1);wordC=TC(:,2);dataC=TC(:,3:11);no=cell2mat(noC);data=cell2mat(dataC);L=size(wordC);L=L(1);word=[];%原表格有错误,根据网络数据进行修正wordC{36}="clean";wordC{247}="trash";%修正endfori=1:L......
  • 软件测试学习笔记丨JMeter_实现分组并发
    Jmeter_实现分组并发实现思路:线程数和时间进行参数化,使用命令模式进行执行,再添加报告进行每次展示。执行时可以使用linux定时器或者脚本调用。命令执行命令启动jmeter命令:jmeter-Jpara1=4-Jpara2=15-n-tpreClassMenu_1117.jmx-le:/res/res1.jtl-e-oe:/res/res/......
  • [刷题笔记] ybt 1364:二叉树遍历(flist)
    Problem_LinkDescription树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。Analysis我们先前做过给定前序......
  • P4220 通道笔记
    边分治神题。前置知识:边分治,虚树。题意给定$3$棵有边权的树,每棵树都含有$n$个节点,令$dis_i(x,y)$表示$(x,y)$在第$i$棵树上的距离。求一组$(i,j)$,使得$\sum\limits_{k=1}^3dis_k(i,j)$最大,为了方便,只需输出最大值。题解考虑边分治。下......
  • 动态 DP 学习笔记
    动态DPP4719动态DP给定一棵\(n\)(\(n\leqslant10^5\))个点的树,点带点权。有\(m\)(\(m\leqslant10^5\))次操作,每次操作给定\(x,y\),表示修改点\(x\)的权值为\(y\)。你需要在每次操作之后求出这棵树的最大权独立集的权值大小。首先考虑\(m=0\)时的做法,可以......
  • 哪款笔记软件支持电脑和手机互通数据?
    上班族在日常工作中,随手记录工作笔记已成为司空见惯的场景。例如:从快节奏的会议记录到灵感迸发的创意;跟踪项目进展,记录每个阶段的成果、问题和下一步计划;记录、更新工作任务清单等,工作笔记承载了职场人士丰富多彩的工作生活。为了能够随时随地记录工作事项,越来越多的职场人士提出......
  • 白话机器学习算法入门笔记
    机器学习中常见的十大算法包括:1.线性回归(LinearRegression)-用于预测连续值的简单线性回归模型。2.逻辑回归(LogisticRegression)-用于分类问题的logistic回归模型。3.决策树(DecisionTree)-一种流行的树形分类与回归方法。4.支持向量机(SVM)-一种二分类模型,Fi......
  • KMP 学习笔记
    前言——\(char\)与\(string\)有的时候\(char\)数组确实比\(string\)好用,且字符串长度很大时\(string\)会被卡掉,所以不要犯懒,老实用\(char\),\(string\)可以用但是慎用。同时很多情况下为了方便和减少出错,我们会想办法把字符串的坐标从\(0\simlen-1\)变成\(1......
  • 【学习笔记】 - 可持久化数据结构初步:可持久化线段树
    前置知识:权值线段树权值线段树每个节点不再是区间,而是值在某个范围内的个数可以用于求区间第\(k\)大值动态开点一个点只有在需要时才被创建正文什么是可持久化数据结构就是说这个数据结构能保留每一个历史版本且支持操作可持久化线段树又称函数式线段树/主席树......