尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

LCA三种算法,轻重链剖分板子记录

LCA三种算法,轻重链剖分板子记录
📅 发布时间:2026/7/14 21:29:50

LCA三种算法,轻重链剖分板子记录

本篇用于给本蒟蒻回忆板子

一.倍增LCA

dfs预处理深度和ST跳跃表,再从高二进制位向低二进制位遍历进行跳跃(与快速幂的思想一致,本质都是一个数能够被转化为二进制)。

先跳到同一层,判断此时是不是LCA,如果不是,再二进制位从高到低遍历,如果遇到跳越后仍然不在同一点的情况,俩个点可以同时直接跳跃;

最后俩个点的父节点是共同的,即为他们的LCA。

ST表的处理原理如下:2i=2i-1+2i-1因此这一块就直接从低到高枚举即可(往上跳的过程均从高到低)

vector<int> dep;
vector<vector<int>> up;
vector<int> e[N];
void dfs(int u,int fa){dep[u]=dep[fa]+1;up[u][0]=fa;for(int i=1;i<=20;i++)up[u][i]=up[up[u][i-1]][i-1];for(auto v:e[u]){if(v==fa)continue;dfs(v,u);}
}
int lca(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)if(dep[up[x][i]]>=dep[y])x=up[x][i];if(x==y)return x;for(int i=20;i>=0;i--){if(up[x][i]!=up[y][i]){x=up[x][i];y=up[y][i];}}return up[x][0];
}

二.Tarjan离线LCA

先自根向下把整棵树打上标记,然后在退出dfs的过程中,自下向上地进行离线处理查询:

从叶子节点开始把每条退出dfs经过的边用并查集合并,这样就可以在子树的范围内就可以把俩个节点的LCA直接处理掉,不会意外得拿更高层级的LCA作为答案。

image

image

DSU dsu(N);
vector<int> e[N];
vector<pair<int,int>> qy[N];
vector<int> ans(N,0);
int vis[N];
void dfs(int u,int fa){vis[u]=1;for(auto v:e[u]){if(!vis[v]){dfs(v,u);dsu.fa[v]=u;}}for(auto [v,i]:qy[u]){if(!vis[v] || ans[i])continue;ans[i]=dsu.find(v);}
}

三.树链剖分LCA

思想可以类比倍增LCA。将树剖分为链之后可以将要查询的u,v俩点跳跃到同一条重链上,然后比较深度来确定谁是最近公共祖先。

对于u,v俩点,while(top[u]!=top[v])时,可以找到深度更深的重链的链头,之后爬到该链头的父节点进入下一条重链,直至u,v俩点在同一重链

第一次dfs完成父节点(fa),子树大小(sz),重儿子(son)的预处理;第二次dfs完成链头数组的处理

int n,m,root;
vector<int> e[N];
int fa[N],dep[N],son[N],sz[N],top[N];
void dfs1(int u,int f){fa[u]=f,dep[u]=dep[f]+1,sz[u]=1;for(auto v:e[u]){if(v==f)continue;dfs1(v,u);sz[u]+=sz[v];if(sz[son[u]]<sz[v])son[u]=v;}
}
void dfs2(int u,int t){top[u]=t;if(!son[u])return;dfs2(son[u],t);for(auto v:e[u]){if(v==fa[u] || v==son[u])continue;dfs2(v,v);}
}
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]];}return dep[u]<dep[v]?u:v;
}

四.轻重链剖分

重链剖分部分与3大差不差,在其基础上,我们对每个节点重新按照重链自上向下递归编号;

  1. 这样一条重链的所有编号就是连续的;
  2. 而一个以u为根的子树中的所有节点,也都是在一个连续的区间当中的;

  因为对于一棵子树来说,会先把重链标号,而在重链节点不断向下递归的过程中会访问其他轻儿子节点,进而当子树重新递归回根节点时,整棵子树都已经被完全编号,且编号连续,为一个区间。之后利用重链上新节点是区间连续的,这一特性,我们利用线段树去维护区间信息;又树上的任意一条路径最多被分为logn条重链的部分,只需要对这几条重链的区间分别操作就可以快速维护整条路径的修改或查询。洛谷p3384板子

#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define lc id<<1
#define rc id<<1|1
const int N=1e5+5;
vector<int> e[N];
int n,m,root,mod,w[N];
int fa[N],son[N],sz[N],dep[N];
int top[N],id[N],nw[N],idx;
void dfs1(int u,int f){fa[u]=f;sz[u]=1;dep[u]=dep[f]+1;for(int v:e[u]){if(v==f)continue;dfs1(v,u);sz[u]+=sz[v];if(sz[son[u]]<sz[v])son[u]=v;}
}
void dfs2(int u,int t){top[u]=t;id[u]=++idx,nw[idx]=w[u];if(!son[u])return;dfs2(son[u],t);for(int v:e[u]){if(v==fa[u] || v==son[u])continue;dfs2(v,v);}
}struct pi{int l,r;int sum,add;
}tr[N*4];
void pushup(int id){tr[id].sum=(tr[lc].sum+tr[rc].sum)%mod;
}
void pushdown(int id){if(!tr[id].add)return;tr[lc].sum=(tr[lc].sum+tr[id].add*(tr[lc].r-tr[lc].l+1))%mod;tr[rc].sum=(tr[rc].sum+tr[id].add*(tr[rc].r-tr[rc].l+1))%mod;tr[lc].add=(tr[lc].add+tr[id].add)%mod;tr[rc].add=(tr[rc].add+tr[id].add)%mod;tr[id].add=0;
}
void build(int id,int l,int r){tr[id]={l,r,nw[l]%mod,0};if(l>=r)return;int md=(l+r)>>1;build(lc,l,md);build(rc,md+1,r);pushup(id);
}
void chg0(int id,int x,int y,int k){int l=tr[id].l,r=tr[id].r;if(x<=l && r<=y){tr[id].sum=(tr[id].sum+(r-l+1)*k)%mod;tr[id].add=(tr[id].add+k)%mod;return;}pushdown(id);int md=(l+r)>>1;if(x<=md)chg0(lc,x,y,k);if(y>md)chg0(rc,x,y,k);pushup(id);
}
void chg1(int u,int v,int k){while(top[u]!=top[v]){if(dep[top[u]]<dep[top[v]])swap(u,v);chg0(1,id[top[u]],id[u],k);u=fa[top[u]];}if(dep[u]<dep[v])swap(u,v);chg0(1,id[v],id[u],k);
}
void chg3(int u,int k){int l=id[u],r=id[u]+sz[u]-1;chg0(1,l,r,k);
}
int query0(int id,int x,int y){int l=tr[id].l,r=tr[id].r;if(x<=l && r<=y)return tr[id].sum;pushdown(id);int md=(l+r)>>1;int res=0;if(x<=md)res=(res+query0(lc,x,y))%mod;if(y>md)res=(res+query0(rc,x,y))%mod;return res;
}
int query2(int u,int v){int res=0;while(top[u]!=top[v]){if(dep[top[u]]<dep[top[v]])swap(u,v);res=(res+query0(1,id[top[u]],id[u]))%mod;u=fa[top[u]];}if(dep[u]<dep[v])swap(u,v);res=(res+query0(1,id[v],id[u]))%mod;return res;
}
int  query4(int u){int l=id[u],r=id[u]+sz[u]-1;return query0(1,l,r);
}
void solve(){cin>>n>>m>>root>>mod;for(int i=1;i<=n;i++)cin>>w[i];for(int i=1;i<n;i++){int u,v;cin>>u>>v;e[u].push_back(v);e[v].push_back(u);}dfs1(root,0);dfs2(root,root);build(1,1,idx);int op,x,y,z;for(int i=1;i<=m;i++){cin>>op;if(op==1){cin>>x>>y>>z;chg1(x,y,z);}else if(op==2){cin>>x>>y;cout<<query2(x,y)<<'\n';}else if(op==3){cin>>x>>y;chg3(x,y);}else{cin>>x;cout<<query4(x)<<'\n';}}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int _=1;//cin>>_;while(_--)solve();
}

 

相关新闻

  • 2026 年旬阳有实力的平推螺杆式启闭机定做厂家哪个好,它为何能无声无息控住万吨洪水?真相令人后背发凉 - 行业严选官
  • C++项目集成Redis实战:从Hiredis编译到连接池封装
  • ONVIF、GB28181、RTSP…国标GB28181视频监控平台EasyCVR视频融合云平台多协议接入一篇搞懂

最新新闻

  • 长沙雨花区厨卫改造|维小达 厨房翻新整体改造、卫生间翻新改造、墙地铺贴、厨卫防水重做、橱柜门窗柜体拆装维保、下水整改全屋厨卫一站式改造翻新服务 - 一点传媒
  • AI转型瓶颈破解:不靠多模型,关键先建企业知识库!打造爆款AI落地核心策略
  • 多轮 Agent 会话爆雷?7 套工程化解决方案,从 90% 幻觉到 97% 可用!
  • 南城公司注册|东莞南城初创企业工商代办合规指南 - GrowUME
  • Windows C盘空间清理与系统优化实战指南
  • 2026年AI降本增效工具平台核心技术解析

日新闻

  • AWS SSM安全运维实践:零公网暴露的合规远程开发方案
  • Tableau 2024.1 图表选择指南:5种业务场景与最佳图表类型匹配
  • dsPIC33FJ与CMT-8540S-SMT在嵌入式音频处理中的高效应用

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号