倍增

这是最最最常见的写法了,一个fa[N][logN]的数组直接搞定

时间复杂度也不算太高

预处理 $ O(nlogn) $ 如果你想卡的话,可以卡到 $ O(nlogh) $ h为树的深度

查询 $ O(2*logn) $ 最坏,平均 $ O(logn) $

$ code $

int dfn[N],cnt;
int dep[N],fa[N][21],siz[N];
void dfs_first(int x){
dfn[x]=++cnt;
siz[x]=1;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x][0])continue;
fa[y][0]=x;
for(re i=1;i<=20;i++)fa[y][i]=fa[fa[y][i-1]][i-1];//cout<<fa[y][i]<<endl;
dep[y]=dep[x]+1;
dfs_first(y);
siz[x]+=siz[y];
}
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(re i=20;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y)return x;
for(re i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}

注意::::dep[1]要赋值为1,否则求取LCA时就全是0了

RMQ

这个真是神级算法了

利用RMQ的原理找到LCA

为什么呢? 因为在两个点的之间,最近的公共祖先一定是,这两个点的dfs序中,深度最小的那个

这样问题就转化成了在区间上求最小值,也就是RMQ问题

最最最恐怖的是他的时间复杂度

预处理与倍增相同 $ O(nlogn) $ 不能卡到h

但是查询快爆了 $ O(1) $

$ code $

int dfn[N],cnt;
int dep[N],fa[N];
int st[N][21],lg2[N];
void dfs_first(int x){
dfn[x]=++cnt;
st[cnt][0]=x;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x])continue;
fa[y]=x;
dep[y]=dep[x]+1;
dfs_first(y);
}
}
void get_st(){
for(re i=2;i<=n;i++)lg2[i]=lg2[i>>1]+1;
for(re j=1;j<=20;j++){
for(re i=1;i+(1<<j)-1<=n;i++){
int r=i+(1<<j-1);
st[i][j]=dep[st[i][j-1]]<dep[st[r][j-1]]?st[i][j-1]:st[r][j-1];
}
}
}
int LCA(int x,int y){
x=dfn[x];y=dfn[y];
if(x>y)swap(x,y);
int tmp=lg2[y-x+1];
return dep[st[x][tmp]]<dep[st[y-(1<<tmp)+1][tmp]]?st[x][tmp]:st[y-(1<<tmp)+1][tmp];
}

所以这个还是比倍增稍微快一点的

树链剖分

这个更快不信你往下看

就是简单的根据树链剖分的top一直往上跳

我们分析一下复杂度

预处理 $ O(2*n) $ 这个完全没有争议

查询,这个查询总起来是比倍增快一些的

因为一般的题不会给你出一颗满二叉树,所以我们每次向上跳,会远远少于logh

毕竟如果每次节点都在轻链上,高度就是logn,没有争议,比倍增快

除非他卡你,就算卡你,你也是logn,快快快快爆了

所以查询的复杂度是 $ O(logn) $ 但是实际应用时,比这个快多了

$ code $

int dfn[N],cnt,fa[N];
int siz[N],son[N],dep[N],top[N];
void dfs1(int x){
dfn[x]=++cnt;siz[x]=1;son[x]=0;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x])continue;
fa[y]=x;dep[y]=dep[x]+1;
dfs1(y);siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs2(int x,int f){
top[x]=f;
if(son[x])dfs2(son[x],f);
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==son[x]||y==fa[x])continue;
dfs2(y,y);
}
}
int LCA(int x,int y){
//cout<<x<<" "<<y<<" "<<top[x]<<" "<<top[y]<<endl;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}

所以就完事了

所以好像昂还有一个tarjan的离线算法

好像弱爆了,所以我基本不用他

最新文章

  1. 用SSH访问内网主机的方法
  2. SAP中需要记住的一些标准表
  3. SQL Server编程(05)游标【转载】
  4. winkawaks模拟器
  5. linux下转换U盘文件系统
  6. 回车和换行在linux下和windows下
  7. UI-popup
  8. Visual Studio 调用 Delphi DLL 会退出的解决方案
  9. 优秀的弹窗插件 jquery.lightbox_me.js
  10. CSS预处理器的对比 — Sass、Less和Stylus
  11. 使用ViewPagerAdapter 页面引导适配器设置app启动页,引导页面的实现
  12. 2017-2018-2 『网络对抗技术』Exp1:PC平台逆向破解 20165335
  13. Django项目创建
  14. unity插件各领域王者
  15. 站在DevOps肩膀上的TestOps(一)
  16. Window配置环境变量
  17. qt 提高图片加载速度
  18. Android控件第1类——TextView
  19. Centos7安装elasticsearch、logstash、kibana、elasticsearch head
  20. 如何给unity3d工程加入依赖的android工程

热门文章

  1. 分布式日志传输系统Databus(一)--系统介绍
  2. [Qt] 事件机制(一)
  3. Tomcat修改jdk版本
  4. C语言中位运算异或“∧”的作用
  5. GNU Linux启动时文件系统mountall挂载出错问题的处理
  6. 关于Ajax 的 cache 属性 (Day_34)
  7. System Verilog设计例化和连接
  8. systemverilog动态数组
  9. Pandas之:Pandas高级教程以铁达尼号真实数据为例
  10. Windows下Qt VS 打包程序 到他人电脑安装运行出现的问题