求LCA 倍增法

倍增法

在线算法,单独处理每个查询

DFS()------祖先递推 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

f a x i faxi faxi表示从 x x x向上跳 2 i 2^i 2i步能到达的祖先
f a x i = f a f a \[ x i − 1 ] i − 1 faxi=fafa\[xi-1]i-1 faxi=fafa\[xi−1]i−1

右端: f a x i − 1 faxi-1 faxi−1=从 x x x向上跳 2 i − 1 2^{i-1} 2i−1步到达的点,从这个点再跳 2 i − 1 2^{i-1} 2i−1能到达 f a x i faxi faxi

利用二进制特征能跳到任意步的祖先

LCA()------同步上跳 O ( m l o g 2 n ) O(mlog_2n) O(mlog2n)

基本思路

  • 把x\y提到相同深度
  • 让x\y同步向上走,每走一步判断是否相遇

例1:零食采购

摘自题解:

列表项第i种零食是否包含 = 起始节点买到第i种零食总数 + 终点买到第i种零食总数 - 公共祖先买到第i种零食总数 - 公共祖先上一个节点买到第i种零食总数

cpp 复制代码
const int N = 1e5+10,M=1050;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e18 ;
int fa[N][25],dep[N];
int c[N][25];
// 分每种零食来统计 看这种零食能不能在路上买到 而不是直接统计种数
vector<int>g[N];

void dfs(int now,int f){
  forr(i,1,20)c[now][i]+=c[f][i];
  dep[now]=dep[f]+1;

  fa[now][0]=f;
  for(int i=1;(1<<i)<=dep[now];i++){
    fa[now][i]=fa[fa[now][i-1]][i-1];
  }

  for(auto x:g[now]){
    if(x==f)continue;
    dfs(x,now);
  }
}

int lca(int x,int y){
  if(dep[x]<dep[y])swap(x,y);//x深 y浅
  //xy提到相同深度
  reforr(i,0,20){
    if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
    //从大到小遍历 利用二进制特性 分解dep[x]-dep[y]
  }
  if(x==y)return x;
  //xy同步上跳
  reforr(i,0,20){
    if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    //不是同一祖先就上跳 逐步逼近LCA
    //fa[x][i]=fa[y][i]时不变 因为会有更近的相同祖先
  }
  return fa[x][0];
}
void solve(){ 
  int n,q;cin>>n>>q;
  forr(i,1,n){
    int cx;cin>>cx;
    c[i][cx]=1;
  }
  forr(i,1,n-1){
    int u,v;cin>>u>>v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  dfs(1,0);// 以1为根 
  
  forr(i,1,q){
    int ans=0;
    int s,t;cin>>s>>t;
    int f=lca(s,t);
    forr(k,1,20){// 统计每种零食是否存在
      int cnt=c[s][k]+c[t][k]-c[f][k]-c[fa[f][0]][k];
      ans+=(cnt>0);
    }
    cout<<ans<<endl;
  }
  
}
相关推荐
AC赳赳老秦6 小时前
OpenClaw批量任务队列优化:解决任务堆积、执行缓慢、优先级混乱问题
java·大数据·数据库·c++·自动化·php·openclaw
晚风予卿云月6 小时前
《二分答案》算法练习
数据结构·c++·算法·二分·竞赛·算法随笔
郭涤生6 小时前
C++ 各类数据的内存分区与读写性能详解
开发语言·c++
j_xxx404_6 小时前
Linux 线程日志系统设计:从策略模式、RAII 到 pthread 线程安全与内核写入路径|附源码
linux·运维·服务器·开发语言·c++·人工智能·策略模式
普马萨特6 小时前
搜索核心算法:从召回到排序
算法·搜索引擎
sheeta19986 小时前
LeetCode 每日一题笔记 日期:2026.05.31 题目:2126. 摧毁小行星
笔记·算法·leetcode
INGNIGHT6 小时前
984.不含 AAA 或 BBB 的字符串(贪心)
开发语言·算法·leetcode
飞天狗1116 小时前
2025第十六届蓝桥杯c/c++B组国赛题解
c语言·c++·算法·蓝桥杯
超梦dasgg6 小时前
Tarjan算法解 强连通分量 & 循环依赖
算法·深度优先·图论
努力努力再努力wz7 小时前
【Qt入门系列】:QLabel控件详解:从文本显示到图片展示,再到内容布局与伙伴机制
android·开发语言·数据结构·数据库·c++·qt·mysql