【模板】【图论】最近公共祖先(LCA)
来源:互联网 发布:mac连不上wifi 编辑:程序博客网 时间:2024/05/29 17:53
1.树上倍增
时间复杂度
在线算法
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;const int mxn =500003,mxm =500003;struct Edge{ int nx,to,val;}e[mxm*2];int n,m,s,ecnt,depth;int hd[mxn],dep[mxn],f[mxn][25];inline int read()//读入优化{ int x=0,sign=1; char c=' '; while(c<'0'||c>'9') { c=getchar(); if(c=='-') sign=-1; } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return sign*x;}inline void add_edge(int u,int v){ e[++ecnt].nx=hd[u]; hd[u]=ecnt; e[ecnt].to=v;}void dfs(int u){ for(int i=hd[u];i;i=e[i].nx) { int v=e[i].to; if(dep[v]) continue; dep[v]=dep[u]+1; f[v][0]=u; dfs(v); }}inline int LCA(int u,int v){ if(dep[u]>dep[v]) swap(u,v); int d=dep[v]-dep[u]; for(int i=0;i<=depth;i++) if(d&(1<<i)) v=f[v][i]; if(u==v) return u; for(int i=depth;i>=0;i--) { if(f[u][i]!=f[v][i]) { u=f[u][i]; v=f[v][i]; } } return f[u][0];}int main(){ n=read();m=read();s=read(); depth=log(n)/log(2)+1; for(int i=1;i<=n-1;i++) { int u,v; u=read();v=read(); add_edge(u,v); add_edge(v,u); } dep[s]=1; dfs(s); for(int j=1;j<=depth;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for(int i=1;i<=m;i++) { int u,v; u=read();v=read(); printf("%d\n",LCA(u,v)); } return 0;}
2.树链剖分
时间复杂度
常数小
在线算法
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;const int mxn =500003,mxm=500003;struct Edge{ int nx,to,val;}e[mxm*2];int hd[mxn],fa[mxn],son[mxn],dep[mxn],top[mxn],siz[mxn],ecnt;int n,m,s;inline int read(){ char c=' '; while(c<'0'||c>'9') c=getchar(); int x=0; while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x;}inline void add_edge(int u,int v){ e[++ecnt].nx=hd[u]; hd[u]=ecnt; e[ecnt].to=v;}inline void dfs1(int u)//求每个点的深度、子树大小和重儿子{ siz[u]=1; dep[u]=dep[fa[u]]+1; for(int i=hd[u];i;i=e[i].nx) { int v=e[i].to; if(fa[u]==v||fa[v]) continue; fa[v]=u; dfs1(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; }}inline void dfs2(int u)//求每个节点的链顶{ if(u==son[fa[u]]) top[u]=top[fa[u]]; else top[u]=u; for(int i=hd[u];i;i=e[i].nx) { int v=e[i].to; if(fa[v]==u) dfs2(v); }}inline int LCA(int u,int v){ while(top[u]!=top[v])//不断把当前较深的节点跳到链顶,直到两个节点在一条链上 dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]]; return dep[u]<dep[v]?u:v;//当两个节点在同一条链上时,深度较浅的就是LCA}int main(){ n=read(); m=read(); s=read(); for(int i=1;i<=n-1;i++) { int u,v; u=read(); v=read(); add_edge(u,v); add_edge(v,u); } dep[s]=1; dfs1(s); dfs2(s); for(int i=1;i<=m;i++) { int u,v; u=read(); v=read(); printf("%d\n",LCA(u,v)); } return 0;}
3.tarjan算法
时间复杂度
离线算法
跑的飞快
PS:Tarjan老爷子真是强,顺手膜一把
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;const int mxn =500003,mxm =500003;//mxn代表最大节点数,mxm代表最大询问数 struct Edge{ int to,nx;}e[mxn*2];//邻接表存边 struct Query{ int to,nx,num;}q[mxm*2];//邻接表存储询问,num代表询问编号 bool vis[mxn];//vis数组代表该节点是否访问过 int hd[mxn],hq[mxm],f[mxn],ans[mxm];//hd和hq分别代表邻接表和询问的头指针 int ecnt=0,qcnt=0;//当前边编号,当前询问编号 inline int read()//读入优化 { char c=' '; while(c<'0'||c>'9') c=getchar(); int x=0; while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x;}int find(int x){ return f[x]==x?x:f[x]=find(f[x]);}//并查集 inline void add_edge(int u,int v)//加边 { e[++ecnt].nx=hd[u]; hd[u]=ecnt; e[ecnt].to=v;}inline void add_query(int u,int v,int num)//加询问 { q[++qcnt].nx=hq[u]; hq[u]=qcnt; q[qcnt].to=v; q[qcnt].num=num;}void LCA(int u,int fa)//对树进行dfs,递归求解LCA { vis[u]=true;//标记当前节点 for(int i=hd[u];i;i=e[i].nx)//以当前节点为根节点,寻找所有儿子 { int v=e[i].to; if(vis[v]||v==fa) continue; LCA(v,u); f[v]=u;//把v合并到当前根节点 } for(int i=hq[u];i;i=q[i].nx)//在遍历完当前节点u的子树后进行此操作 { int v=q[i].to; int num=q[i].num; if(vis[v]) ans[num]=find(v);//如果u没有被访问过,v被访问过,那么u和v的LCA就是find(v) }}int main(){ int n,m,s; n=read();m=read();s=read(); for(int i=1;i<=n;i++) f[i]=i;//并查集初始化 for(int i=1;i<=n-1;i++) { int u,v; u=read();v=read(); add_edge(u,v); add_edge(v,u);//把树当成无向图处理 } for(int i=1;i<=m;i++)//离线处理,先把所有询问记下来 { int u,v; u=read();v=read(); add_query(u,v,i); add_query(v,u,i);//当询问u,v的LCA时,把u v和v u同时存储,便于更新答案 } LCA(s,0); for(int i=1;i<=m;i++) printf("%d\n",ans[i]);//按编号顺序输出答案 return 0;}
阅读全文
1 0
- 【模板】【图论】最近公共祖先(LCA)
- LCA----【模板】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- P3379 【模板】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- 最近公共祖先LCA【模板】
- [模板]最近公共祖先LCA
- 【模板】lca 最近公共祖先
- LCA(最近公共祖先)
- 【最近公共祖先(LCA)】
- 最近公共祖先(LCA)
- 最近公共祖先(LCA)
- LCA(最近公共祖先)
- 【讲解+模板】最近公共祖先(LCA)(倍增)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- lca(最近公共祖先)倍增模板【pascal】
- 最近公共祖先LCA模板(Tarjan/RMQ)
- viewpager设置子item宽度
- openwrt编写hello_world ipk
- MVC模式 探索
- hdu 1392(凸包)
- top n with ties
- 【模板】【图论】最近公共祖先(LCA)
- 8.15 N
- 文章标题 【Java源码浅析】关于HashMap和HashSet的异同和源码分析
- C Primer Plus 第二章
- Spring Bean的自动装配,注入及后处理器
- A
- memcached安装
- FileChannel通道 NIO 读写
- 人生感悟文章(链接)