st表

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int go[];
int nxt[];
int adj[];
int pos[];
int st[][];
int dep[];
int aa[];
int lg[];
int ecnt,cnt,m,n,s,x,y,a,b;
void add(int u,int v) { //建链前
go[++ecnt]=v;
nxt[ecnt]=adj[u];
adj[u]=ecnt;
}
void dfs(int u,int pre) {
dep[u]=dep[pre]+; //首先预处理出深度
aa[++cnt]=u; //DFS序
pos[u]=cnt; //第几个出现的
for(int e=adj[u]; e; e=nxt[e]) {
if(go[e]!=pre) {
dfs(go[e],u);
aa[++cnt]=u;
}
}
}
int MIN(int p,int q) {
if(dep[p]<dep[q]) return p;
else return q;
}
void build() {
for(int i=; i<=cnt; i++) {
st[i][]=aa[i];
}
for(int i = , j = ; i <= cnt; i++){
if( << (j + ) == i) j++;
lg[i] = j;
}
for(int j=; j<=lg[cnt]; j++) {
for(int i=; i + ( << j) - <=cnt; i++) {
st[i][j]=MIN(st[i][j-],st[i+( << (j - ))][j-]);
}
}
}
/*
读入两个节点,查询它们第一次出现的位置
在这两个位置之间的区间查询最小深度的节点,该节点即为最近公共祖先
*/
int lca(int l,int r) {
int xx=pos[l];
int yy=pos[r];
if(xx>yy) swap(xx,yy);
int k=lg[yy-xx+];
return MIN(st[xx][k],st[yy-( << k)+][k]);
}
template <class T> //快速读入
void read(T &x){
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T> //快速输出
void write(T x){
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
int main() {
//scanf("%d%d%d",&n,&m,&s);
read(n), read(m), read(s);
for(int i=; i<=n-; i++) {
//scanf("%d%d",&x,&y);
read(x), read(y);
add(x,y);
add(y,x);
}
dfs(s,);
build();
for(int i=; i<=m; i++) {
//scanf("%d%d",&a,&b);
//printf("%d\n",lca(a,b));
read(a), read(b);
write(lca(a, b)), putchar('\n');
}
return ;
}

树上倍增和st表的思路一样,只是实现方法不同

/*
倍增求LCA:
father【i】【j】表示节点i往上跳2^j次后的节点
可以转移为
father【i】【j】=father【father【i】【j-1】】【j-1】
(此处注意循环时先循环j,再循环i)
然后dfs求出各个点的深度depth
整体思路:
先比较两个点的深度,如果深度不同,先让深的点往上跳,浅的先不动,
等两个点深度一样时,if 相同 直接返回,if 不同 进行下一步;如果不同
,两个点一起跳,j从大到小枚举(其实并不大),如果两个点都跳这么多后
,得到的点相等,两个点都不动(因为有可能正好是LCA也有可能在LCA上方)
,知道得到的点不同,就可以跳上来,然后不断跳,两个点都在LCA下面那层,
所以再跳1步即可,当father【i】【j】中j=0时即可,就是LCA,返回值结束
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
vector <int> g[];
int father[][]={};
int depth[]={};
int n,m;
bool visit[]={false};
int root;
void dfs(int u)//深搜出各点的深度,存在depth中
{
int i;
visit[u]=true;
for (i=;i<g[u].size();i++)
{
int v=g[u][i];
if ( !visit[v] )
{
depth[v]=depth[u]+;
dfs(v);
}
}
}
void bz()//fa数组的预处理
{
int i,j;
for (j=;j<=;j++)
for (i=;i<=n;i++)
father[i][j]=father[father[i][j-]][j-];
}//倍增,处理father数组,详情参照上述讲解
int LCA(int u,int v)
{
if ( depth[u]<depth[v] )
{
int temp=u;
u=v;
v=temp;
}//保证深度大的点为u,方便操作
int dc=depth[u]-depth[v];
int i;
for (i=;i<;i++)//值得注意的是,这里需要从零枚举
{
if ( (<<i) & dc)//从大到小二分
u=father[u][i];//意思是跳2^j步不一样,就跳,否则不跳
}
//上述操作先处理较深的结点,使两点深度一致
if (u==v) return u;//如果深度一样时,两个点相同,直接返回
for (i=;i>=;i--)//从大到小二分。
{
if (father[u][i]!=father[v][i])//跳2^j步不一样,就跳,否则不跳
{
u=father[u][i];
v=father[v][i];
}
}
u=father[u][];//上述过程做完,两点都在LCA下一层,所以走一步即可
return u;
}
int main()
{
int i,j;
scanf("%d",&n);
for (i=;i<=n;i++)
g[i].clear();
for (i=;i<n;i++)
{
int a,b;
int root;
scanf("%d%d",&a,&b);
g[a].push_back(b);
father[b][]=a;//a^0为1,所以fa[a][0]代表a向上走一格
if (father[a][]==)//如果节点的根为0,证明该节点为根节点
root = a;
}
depth[root]=;
dfs(root);
bz();
int x,y;
scanf("%d%d",&x,&y);
printf("%d",LCA(x,y));
return ;
}

LCA__st算法&&树上倍增的更多相关文章

  1. [算法]树上倍增求LCA

    LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...

  2. bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增

    题意:给你一个n个点m条边的图,有若干组询问,每次询问会选择图中的一些边删除,删除之后问此图是否联通?询问之间相互独立.此题强制在线. 思路:首先对于这张图随便求一颗生成树,对于每一条非树边,随机一个 ...

  3. 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法

    题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...

  4. 最近公共祖先算法LCA笔记(树上倍增法)

    Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...

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

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

  6. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  7. 两种lca的求法:树上倍增,tarjan

    第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...

  8. LCA树上倍增

    LCA就是最近公共祖先,比如 节点10和11的LCA就是8,9和3的LCA就是3. 我们这里讲一下用树上倍增来求LCA. 大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点. ...

  9. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...

随机推荐

  1. 后台中的sql注入

    aa.getSqlMap().put("order"," and a.id not in(\'"+po.getId()+"\')"); \' ...

  2. Java基础——从数组到集合之间关键字的区别!!!!

    1.&& 和 &区别和联系: 相同点 : 结果是一样的.       不同点 :如果使用双&号判断,如果说条件一为false,不会判断条件二,但是单&号会继续判 ...

  3. 2018NOIP普及T4---对称二叉树

    题目 对称二叉树   题目描述 思路 检查是否符合对称条件 条件很简单——结构对称&&点权对称 要做到点权对称其实也就顺便结构对称了 于是条件可以简化为点权对称 可以考虑并行搜索 bo ...

  4. 洛谷——P3369 【模板】普通平衡树(splay)(基础splay,维护一些神奇的东东)

    P3369 [模板]普通平衡树 平衡树大法好,蒟蒻(博主)最近正在收集高级数据结构的碎片,企图合成数据结构的元素之力来使自己的RP++... 您需要写一种数据结构(可参考题目标题),来维护一些数,其中 ...

  5. Python学习第二阶段,Day2,import导入模块方法和内部原理

    怎样导入模块和导入包?? 1.模块定义:代码越来越多的时候,所有代码放在一个py文件无法维护.而将代码拆分成多个py文件,同一个名字的变量互不影响,模块本质上是一个.py文件或者".py&q ...

  6. php利用32进制实现对id加密解密

    前言 最近在项目中遇到一个问题,当前用户分享一个邀请码给好友,好友根据邀请码注册成为新用户之后,则成为当前用户的下级,特定条件下,可以得到下级用户的一系列返利.这里要实现的就是根据当前用户的id,生成 ...

  7. buf.readDoubleBE()

    buf.readDoubleBE(offset[, noAssert]) buf.readDoubleLE(offset[, noAssert]) offset {Number} 0 <= of ...

  8. FJoi2017 1月20日模拟赛 恐狼后卫(口糊动规)

    Problem 1 恐狼后卫(wolf.cpp/c/pas) [题目描述] 著名卡牌游戏<石炉传说>中有一张随从牌:恐狼后卫.恐狼后卫的能力是使得相邻随从的攻击力提高. 现在有n张恐狼后卫 ...

  9. 2.8 补充:shell脚本执行方法

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限.   方法一:切换到shell脚本 ...

  10. 第一个Maven工程的目录结构和文件内容及联网问题

    [第一个Maven工程] ①目录结构 Hello |---src |---|---main |---|---|---java |---|---|---resources |---|---test |- ...