时间复杂度:

dfs树,求st表(状态数组f):O(NlgN)

处理M个查询:O(MlgN)

总:O((M+N)lgN)

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=500010;
struct edge{ int t; edge * nxt; edge(int to, edge * next){ t=to, nxt=next; } };
edge * h[maxn];
void add(int u, int v) { h[u]=new edge(v, h[u]); }
int N, M, S, fa[maxn], L[maxn], f[maxn][20]; //S为根节点,fa为父亲数组,L记录结点深度,f为状态数组 inline int read(){
int s=0, w=1; char ch=getchar();
while(ch<'0' || ch>'9' ){ if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
} void dfs(int x){ //在dfs过程中计算出每个节点的深度L、father
L[x]=L[fa[x]]+1;
f[x][0]=fa[x];
for(int i=1; (1<<i)<=L[x]; i++) //使用倍增思想[ST]计算出当前结点的2^i代祖先
f[x][i]=f[f[x][i-1]][i-1];
for(edge * p=h[x]; p; p=p->nxt){
if(p->t==fa[x]) continue;
fa[p->t]=x;
dfs(p->t);
}
} // void prep(){ //这是另一种形式dp计算所有节点的2^k祖宗
// int max_k=log(N)/log(2);
// for(int i=1; i<=N; i++) //依赖于dfs得到的fa数组作为初始状态
// f[i][0]=fa[i];
// for(int k=1; k<max_k; k++){ //状态转移的时间复杂度为O(NlgN)
// for(int i=1; i<=N; i++){
// if((L[i]-(1<<k))>0)
// f[i][k]=f[f[i][k-1]][k-1]; //但倍增计算放在dfs里面是最巧妙、高效的
// }
// }
// } int lca(int x, int y){
if(x==y) return x; //!!!!!!!!!!!!!非常重要,不用解释!!!!!!!!!!
if(L[x]<L[y]) swap(x, y); //如果x比y浅,交换,使得x比y深
int t=log(L[x]-L[y])/log(2); //计算x,y相差的层数,x最大可以向上跳2^t层
for(int i=t; i>=0; i--){ //从x位置以二进制的方式向上跳
if(L[f[x][i]]>=L[y]) x=f[x][i];
if(x==y) return x;
}
t=log(L[x])/log(2); //距离树根,最多可以向上跳2^t层
for(int i=t; i>=0; i--) //从x, y位置以二进制的方式一同向上跳
if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i]; //father不一样,继续跳
return f[x][0];
} int main(){
N=read(); M=read(); S=read();
for(int i=1, x, y; i<N; i++) { x=read(); y=read(); add(x, y); add(y, x); }
dfs(S);
for(int i=1, a, b; i<=M; i++) { a=read(); b=read(); printf("%d\n", lca(a, b)); }
return 0;
}

LCA(ST倍增)的更多相关文章

  1. 关于LCA的倍增解法的笔记

    emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主 ...

  2. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  3. LCA的倍增算法

    LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...

  4. [模板]LCA的倍增求法解析

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  5. ST&倍增LCA

    回顾st算法,它的一大功能是求区间最值.先将整个区间划分成若干个小的区间,求出最值,然后将小的区间合并成一个大的区间,我们这里要用到一个数组minn[i][j],划重点!如果我们要求的是区间最小值,m ...

  6. [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]

    参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...

  7. 关于树论【LCA树上倍增算法】

    补了一发LCA,表示这东西表面上好像简单,但是细节真挺多. 我学的是树上倍增,倍增思想很有趣~~(爸爸的爸爸叫奶奶.偶不,爷爷)有一个跟st表非常类似的东西,f[i][j]表示j的第2^i的祖先,就是 ...

  8. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  9. LCA算法倍增算法(洛谷3379模板题)

    倍增(爬树)算法,刚刚学习的算法.对每一个点的父节点,就记录他的2k的父亲. 题目为http://www.luogu.org/problem/show?pid=3379 第一步先记录每一个节点的深度用 ...

随机推荐

  1. RHEL6 删除软RAID

    停止使用RAID: 1.umount raid组上的硬盘的所用的分区 若使用raid组创建vg,需要删除或去激活VG 2.停止raid服务 mdadm -S /dev/md0 3.清除MBR # md ...

  2. LeetCode算法题-Shortest Unsorted Continuous Subarray(Java实现)

    这是悦乐书的第267次更新,第281篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第134题(顺位题号是581).给定一个整数数组,找到一个连续的子数组,按升序对该子数组 ...

  3. Python开发【第四篇】函数

    函数的作用 函数可以让编程逻辑结构化以及模块化 无论是C.C++,Java还是Python,函数是必不可少的知识点,也是很重要的知识点,函数是完成一个功能的代码块,使用函数可以使逻辑结构变得更加清晰以 ...

  4. SQL NULL 值

    NULL 值是遗漏的未知数据. 默认地,表的列可以存放 NULL 值. 本章讲解 IS NULL 和 IS NOT NULL 操作符. SQL NULL 值 如果表中的某个列是可选的,那么我们可以在不 ...

  5. CSAPP:第八章 异常控制流2

    CSAPP:第八章 异常控制流2 关键点:进程控制.信号 8.4 进程控制8.5 信号 8.4 进程控制   Unix提供了大量从C程序中操作进程的系统调用.8.4.1 获取进程ID  每个进程都有一 ...

  6. centos docker 安装

    centos docker 安装 参考网站 https://docs.docker.com/install/linux/docker-ce/centos/ 1.删除原有docker $ sudo yu ...

  7. android 图片上传图片 报Socket: Broken pipe

    上传图片的时候报如下错误: 上传失败的原因是服务器限制了文件上传的大小.让服务端改一下配置文件就好了

  8. HNOI2019:My Dream

    反正这次的目标也不是进省队,目标就是做到最好吧-- 下面都是流水账~ Day -INF ~ Day -3 专题交流没什么好说的,模拟赛详见3.11-3.27省选前多校联考乱记和3.28-4.2CJ大毒 ...

  9. 炸弹人游戏开发系列(7):加入敌人,使用A*算法寻路

    前言 上文中我们实现了炸弹人与墙的碰撞检测,以及设置移动步长来解决发现的问题.本文会加入1个AI敌人,敌人使用A*算法追踪炸弹人. 本文目的 加入敌人,追踪炸弹人 本文主要内容 开发策略 加入敌人 实 ...

  10. git修改已push的commit信息

    本条适用于修改已push的最新的commit信息,确保本地的文件是最新的. 使用 git commit --amend 命令,(修改最近一次提交的注释信息),会进入到vim 编辑器 编辑提交信息,保存 ...