POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)
1、输入树中的节点数N,输入树中的N-1条边。最后输入2个点,输出它们的最近公共祖先。
2、裸的最近公共祖先。
3、
dfs+ST在线算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* LCA(POJ 1330) 在线算法 DFS+ST */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=10010; int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列 struct ST{ int mm[2*MAXN]; int dp[2*MAXN][20];//最小值对应的下标 void init(int n){ mm[0]=-1; for(int i=1;i<=n;i++){ mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=i; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } //查询[a,b]之间最小值的下标 int query(int a,int b){ if(a>b)swap(a,b); int k=mm[b-a+1]; return rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; } }; //边的结构体定义 struct Edge{ int to,next; }; Edge edge[MAXN*2]; int tot,head[MAXN]; int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始 int P[MAXN];//P[i]表示点i在F中第一次出现的位置 int cnt; ST st; void init(){ tot=0; memset(head,-1,sizeof(head)); } //加边,无向边需要加两次 void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void dfs(int u,int pre,int dep){ F[++cnt]=u; rmq[cnt]=dep; P[u]=cnt; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==pre)continue; dfs(v,u,dep+1); F[++cnt]=u; rmq[cnt]=dep; } } //查询LCA前的初始化 void LCA_init(int root,int node_num){ cnt=0; dfs(root,root,0); st.init(2*node_num-1); } //查询u,v的lca编号 int query_lca(int u,int v){ return F[st.query(P[u],P[v])]; } bool flag[MAXN]; int main(){ int T; int N; int u,v; scanf("%d",&T); while(T--){ scanf("%d",&N); init(); memset(flag,false,sizeof(flag)); for(int i=1;i<N;i++){ scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); flag[v]=true; } int root; for(int i=1;i<=N;i++) if(!flag[i]){ root=i; break; } LCA_init(root,N); scanf("%d%d",&u,&v); printf("%d\n",query_lca(u,v)); } return 0; }
LCA倍增法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* POJ 1330 LCA在线算法 */ #include<iostream> #include<stdio.h> #include<string.h> #include<queue> using namespace std; const int MAXN=10010; const int DEG=20; struct Edge{ int to,next; }edge[MAXN*2]; int head[MAXN],tot; void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void init(){ tot=0; memset(head,-1,sizeof(head)); } int fa[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先 int deg[MAXN];//深度数组 void BFS(int root){ queue<int>que; deg[root]=0; fa[root][0]=root; que.push(root); while(!que.empty()){ int tmp=que.front(); que.pop(); for(int i=1;i<DEG;i++) fa[tmp][i]=fa[fa[tmp][i-1]][i-1]; for(int i=head[tmp];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==fa[tmp][0])continue; deg[v]=deg[tmp]+1; fa[v][0]=tmp; que.push(v); } } } int LCA(int u,int v){ if(deg[u]>deg[v])swap(u,v); int hu=deg[u],hv=deg[v]; int tu=u,tv=v; for(int det=hv-hu,i=0;det;det>>=1,i++) if(det&1) tv=fa[tv][i]; if(tu==tv)return tu; for(int i=DEG-1;i>=0;i--){ if(fa[tu][i]==fa[tv][i]) continue; tu=fa[tu][i]; tv=fa[tv][i]; } return fa[tu][0]; } bool flag[MAXN]; int main(){ int T; int n; int u,v; scanf("%d",&T); while(T--){ scanf("%d",&n); init(); memset(flag,false,sizeof(flag)); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); flag[v]=true; } int root; for(int i=1;i<=n;i++) if(!flag[i]){ root=i; break; } BFS(root); scanf("%d%d",&u,&v); printf("%d\n",LCA(u,v)); } return 0; }