题意:求最近公共祖先。
解题关键:三种方法,1、st表 2、倍增法 3、tarjan
此次使用倍增模板
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int n,m,root,cnt,u,v,head[500005],dep[500005],fa[500005][21]; struct edge{ int nxt; int to; }e[1000005]; void add_edge(int u,int v){//单向 e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++; } void dfs(int u){ for(int i=1;(1<<i)<=dep[u];i++){ fa[u][i]=fa[fa[u][i-1]][i-1]; } for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if(v==fa[u][0]) continue; fa[v][0]=u; dep[v]=dep[u]+1; dfs(v); } } int lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); int d=dep[u]-dep[v]; for(int i=0;(1<<i)<=d;i++) if(d&(1<<i)) u=fa[u][i];//转化到两节点深度相同,类似于快速幂的思想 if(u==v) return u; for(int i=20;i>=0;i--){ if(fa[u][i]!=fa[v][i]){ u=fa[u][i]; v=fa[v][i]; } } return fa[u][0]; } int main(){ memset(head,-1,sizeof head); scanf("%d%d%d",&n,&m,&root); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs(root); while(m--){ scanf("%d%d",&u,&v); printf("%d\n",lca(u,v)); } return 0; }
2、熟悉的树dp方式
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int n,m,root,cnt,u,v,head[500005],dep[500005],par[500005][21]; struct edge{ int nxt; int to; }e[1000005]; void add_edge(int u,int v){//单向 e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++; } void dfs(int u,int fa){ for(int i=1;(1<<i)<=dep[u];i++){ par[u][i]=par[par[u][i-1]][i-1]; } for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if(v==fa) continue; par[v][0]=u; dep[v]=dep[u]+1; dfs(v,u); } } int lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); int d=dep[u]-dep[v]; for(int i=0;(1<<i)<=d;i++) if(d&(1<<i)) u=par[u][i];//转化到两节点深度相同,类似于快速幂的思想 if(u==v) return u; for(int i=20;i>=0;i--){ if(par[u][i]!=par[v][i]){ u=par[u][i]; v=par[v][i]; } } return par[u][0]; } int main(){ memset(head,-1,sizeof head); scanf("%d%d%d",&n,&m,&root); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs(root,-1); while(m--){ scanf("%d%d",&u,&v); printf("%d\n",lca(u,v)); } return 0; }
原文地址:https://www.cnblogs.com/elpsycongroo/p/10352437.html
时间: 2024-10-07 14:41:56