重链剖分求LCA

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

题目链接

倍增做法求LCA 在 这篇博客中有提到


题目描述


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


输入格式

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

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

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

输出格式


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


输入输出


样例 1

输入

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


输出

4
4
1
4
4


说明/提示


对于 30% 的数据,N≤10,M≤10。

对于 70% 的数据,N≤10000,M≤10000。

对于 100% 的数据,N≤500000,M≤500000。

20210306161539165.jpg

int lca(int u,int v) {
  while(top[u] != top[v]) {
    if(dep[top[u]] < dep[top[v]]) swap(u,v);
    u = fa[top[u]];
  }
  if(dep[u] < dep[v]) return u;
  else return v;
}


对于要求树上两个点u,v的lca,(当两个点不在一条重链上的时候)我们可以每次先让链头深depth比较大的点进行移动,不在一条重链上直接将top更深的节点跳到链头的父节点u = fa[top[u]]; ,当两个点在一条重链上的时候,从深度的角度来看,深度比较小的就应该是祖先节点


int n,m,rt;
struct node {
  int to;
  int nex;
} e[maxn];
int head[maxn],cnt;
void init() {
  for(int i=0; i<maxn; i++) head[i] = -1;
  cnt = 0;
}
void add(int u,int v) {
  e[cnt].to = v;
  e[cnt].nex = head[u];
  head[u] = cnt ++;
}
int fa[maxn],siz[maxn],son[maxn],dep[maxn],top[maxn];
void dfs1(int x) {
  siz[x] = 1;
  dep[x] = dep[fa[x]] + 1;
  for(int i=head[x]; ~i; i=e[i].nex) {
    int to = e[i].to;
    // fa[to] = x;
    if(to != fa[x]) {
      fa[to] = x;
      dfs1(to);
      siz[x] += siz[to];
      if(siz[to] > siz[son[x]]) son[x] = to;
    }
  }
}
void dfs2(int rt,int tp) {
  top[rt] = tp;
  if(son[rt]) dfs2(son[rt],tp);
  for(int i = head[rt]; ~i; i = e[i].nex) {
    int to = e[i].to;
    if(to != fa[rt] && to != son[rt]) dfs2(to,to);
  }
}
int lca(int u,int v) {
  while(top[u] != top[v]) {
    if(dep[top[u]] < dep[top[v]]) swap(u,v);
    u = fa[top[u]];
  }
  if(dep[u] < dep[v]) return u;
  else return v;
}
int main() {
  cin >> n >> m >> rt;
  init();
  for(int i = 1; i < n; i++) {
    int u=read,v=read;
    add(u,v);
    add(v,u);
  }
  dfs1(rt);
  dfs2(rt,rt);
  while(m --) {
    int u=read,v=read;
    cout<<lca(u,v)<<endl;
  }
  return 0;
}



目录
相关文章
|
7月前
【Leetcode -2181.合并零之间的节点- 2326.螺旋矩阵Ⅳ】
【Leetcode -2181.合并零之间的节点- 2326.螺旋矩阵Ⅳ】
43 0
|
8月前
|
存储 C语言 C++
问题 D: DS查找—二叉树平衡因子(不一样的新做法哦)
问题 D: DS查找—二叉树平衡因子(不一样的新做法哦)
|
3天前
|
人工智能
合并果子(哈夫曼树)NOIP2004提高组
合并果子(哈夫曼树)NOIP2004提高组
|
人工智能 算法 BI
LeetCode 周赛 341 场,模拟 / 树上差分 / Tarjan 离线 LCA / DFS
上周末有单双周赛,双周赛我们讲过了,单周赛那天早上有事没参加,后面做了虚拟竞赛,然后整个人就不好了。前 3 题非常简单,但第 4 题有点东西啊,差点就放弃了。最后,被折磨了一个下午和一个大夜总算把第 4 题做出来了,除了新学的 Tarjon 离线算法,这道题还涉及到树上差分、前缀和、DFS、图论等基础知识,几度被折磨得想要放弃。这种感觉,似乎和当年在 LeetCode 上做前 10 题的时候差不多哈哈。
68 0
<<算法很美>>——(七)——DFS典题(一):水洼数目
<<算法很美>>——(七)——DFS典题(一):水洼数目
<<算法很美>>——(七)——DFS典题(一):水洼数目
|
定位技术
【CCCC】L3-005 垃圾箱分布 (30分),Dijkstra跑n遍 = 多源最短路
【CCCC】L3-005 垃圾箱分布 (30分),Dijkstra跑n遍 = 多源最短路
102 0
【CCCC】L2-026 小字辈 (25分),求多叉树的深度和底层叶节点
【CCCC】L2-026 小字辈 (25分),求多叉树的深度和底层叶节点
107 0
CF191C——Fools and Roads(树上边差分+LCA)
CF191C——Fools and Roads(树上边差分+LCA)
104 0
|
人工智能 vr&ar
SPOJ - COT Count on a tree(主席树 LCA)
SPOJ - COT Count on a tree(主席树 LCA)
72 0
ES聚合算法原理深入解读:深度优先算法(DFS)和广度优先算法(BFS)(三)
ES聚合算法原理深入解读:深度优先算法(DFS)和广度优先算法(BFS)(三)
ES聚合算法原理深入解读:深度优先算法(DFS)和广度优先算法(BFS)(三)