标签:lin als 一个 cond bottom uil mat note tree
其实敲树剖敲多了就会手敲,然后就发现其实树剖也是可以求LCA的,根据树剖的经验,我们两遍dfs后关于询问l,r的情况我们就开始跳链,当l,r处于同一个链的时候返回深度较小的那个点就好了,这里给个例题:
题目链接:http://poj.org/problem?id=1330
Description
Input
Output
Sample Input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
Sample Output
4 3
其题目大意是给你T组数据,n,n-1条边,其中第一个点是第二个点的父节点,最后询问a,b的最近公共祖先
那么我们先找到根节点,即没有父节点的那个点就是了,然后走一波树剖的准备过程。。。
以下是树剖式AC代码:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int mac=1e4+10; struct node { int to,next; }eg[mac<<1]; int head[mac],num=0,top[mac],son[mac],dson[mac]; int father[mac],d[mac],cnt=0,f[mac]; void add(int u,int v) { eg[++num]=node{v,head[u]}; head[u]=num; } void dfs2(int x,int tp) { top[x]=tp; if (!dson[x]) return; dfs2(dson[x],tp); for (int i=head[x]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (v==father[x] || v==dson[x]) continue; dfs2(v,v); } } void dfs1(int x,int fa,int dp) { d[x]=dp;father[x]=fa;son[x]=1; int maxson=-1; for (int i=head[x]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (v==fa) continue; dfs1(v,x,dp+1); son[x]+=son[v]; if (son[v]>maxson) dson[x]=v,maxson=son[v]; } } int lca(int l,int r) { while (top[l]!=top[r]){ if (d[top[l]]<d[top[r]]) swap(l,r); l=father[top[l]]; } if (d[l]<d[r]) return l; return r; } void init() { memset(head,-1,sizeof head); num=0;cnt=0; memset(f,0,sizeof f); memset(son,0,sizeof son); memset(dson,0,sizeof dson); memset(d,0,sizeof d); memset(top,0,sizeof top); } int main() { //freopen("in.txt","r",stdin); int t; scanf ("%d",&t); while (t--){ int n; scanf ("%d",&n); init(); for (int i=1; i<=n-1; i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u);f[v]=u; } int rt; for (int i=1; i<=n; i++) if (!f[i]) {rt=i;break;} dfs1(rt,0,1); dfs2(rt,rt); int l,r; scanf("%d%d",&l,&r); printf ("%d\n",lca(l,r)); } return 0; }
接下来就是带权的情况了,实际上我们只需要多加一个dfs就好了,这个dfs求每个点到根节点的距离,那么我们求一波LCA,设该点为p,后用dis[l]+dis[r]-dis[p]*2就完事了。
给个例题:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
以下是AC代码:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int mac=4e4+10; struct node { int to,next,w; }eg[mac<<1]; int head[mac],num=0,top[mac],son[mac],dson[mac]; int father[mac],d[mac],cnt=0,dis[mac]; void add(int u,int v,int w) { eg[++num]=node{v,head[u],w}; head[u]=num; } void dfs2(int x,int tp) { top[x]=tp; if (!dson[x]) return; dfs2(dson[x],tp); for (int i=head[x]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (v==father[x] || v==dson[x]) continue; dfs2(v,v); } } void dfs1(int x,int fa,int dp) { d[x]=dp;father[x]=fa;son[x]=1; int maxson=-1; for (int i=head[x]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (v==fa) continue; dfs1(v,x,dp+1); son[x]+=son[v]; if (son[v]>maxson) dson[x]=v,maxson=son[v]; } } void dfs(int x) { for (int i=head[x]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (v==father[x]) continue; dis[v]=dis[x]+eg[i].w; dfs(v); } } int lca(int l,int r) { while (top[l]!=top[r]){ if (d[top[l]]<d[top[r]]) swap(l,r); l=father[top[l]]; } if (d[l]<d[r]) return l; return r; } void init() { memset(head,-1,sizeof head); num=0;cnt=0; memset(son,0,sizeof son); memset(dson,0,sizeof dson); memset(d,0,sizeof d); memset(top,0,sizeof top); } int main() { //freopen("in.txt","r",stdin); int t; scanf ("%d",&t); while (t--){ int n,q; scanf ("%d%d",&n,&q); init(); for (int i=1; i<=n-1; i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } int rt=1; dfs1(rt,0,1); dfs2(rt,rt); dfs(rt); int l,r; for (int i=1; i<=q; i++){ scanf("%d%d",&l,&r); int anc=lca(l,r); printf("%d\n",dis[l]+dis[r]-dis[anc]*2); } } return 0; }
POJ-1330&HDU-2586 最近公共祖先(不带权+带权)树剖式写法求LCA
标签:lin als 一个 cond bottom uil mat note tree
原文地址:https://www.cnblogs.com/lonely-wind-/p/12196144.html