【UOJ 226】最近公共祖先

【题目描述】:

有根树在计算机科学工程领域是一个人人熟知的数据结构类型。下面是一个例子。

8->(1,4,5);1->(13,14);4->(6,10);5->(9);6->(7,15);10->(2,11,16);16->(3,12);

在这个图中,每个点都是由{1, 2,...,16}中的某个数字标记的。8号点是树的根。如果x号点在y号点到根的路径上,则x是y的祖先。比如4是16的祖先,10也是。事实上,8,4,10,16都是16的祖先。记住,一个节点本身就是自己的祖先。再比如8,4,6,7是7的祖先。

如果x既是y的祖先也是z的祖先则称x是y和z公共祖先。也就是说8和4都是16和7的公共祖先。

如果x在y和z的所有公共祖先中距离y和z最近,则x是y和z的最近公共祖先。也就是说4是16和7的最近公共祖先而不是8,因为4比8更近。

再举一些例子:节点2和3的最近共同祖先是节点10,节点6和13的最近共同祖先是节点8,节点4和12的最近共同祖先是节点4。在最后一个例子中,如果Y是Z的祖先,那么Y和Z的最近共同祖先是Y。

编写一个程序,找出树中两个不同节点的最近共同祖先。

【输入描述】:

第一行,N和M表示节点数和询问数,节点编号1至N;

以下N-1行,每行两个整数a和b,表示a是b的父亲节点;

之后M行,每行两个不相同的数,表示询问它们的最近共同祖先。

【输出描述】:

M行,每行一个数表示对应的询问结果。

【样例输入】:

16 1
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

【样例输出】:

4

【时间限制、数据范围及描述】:

时间:1s 空间:256M

对于 40%的数据:1<=N,M<=3000

对于 100%的数据:1<=N,M<=2×10^5

题解:LCA的一道题,但我们这次用树链剖分的方法做。是一道树链剖分模板T~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=500002;
int yc,n,x,y,m,cnt,head[N];
struct node{
    int to;
    int next;
}e[N];
void add(int a,int b){
    e[++cnt].to=b;
    e[cnt].next=head[a];
    head[a]=cnt;
}
int ta[N],ti[N],son[N],sz[N],dep[N],fa[N],dfsc,top[N];

void dfs1(int u,int pa,int de){
    son[u]=0; sz[u]=1; dep[u]=de; fa[u]=pa;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==pa) continue;
        dfs1(v,u,de+1);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]]) son[u]=v;
    }
}

void dfs2(int u,int pa){
    ti[u]=++dfsc; 
    top[u]=pa;
    if(son[u]!=0) dfs2(son[u],pa);
    //else return;
    for(int i=head[u];i;i=e[i].next)
        if(e[i].to!=son[u] && e[i].to!=fa[u]) 
           dfs2(e[i].to,e[i].to);
}

int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<n;i++) 
       { scanf("%d %d",&x,&y); add(x,y); add(y,x); ta[y]=x; }
    for(int i=1;i<=n;i++)
        if(ta[i]==0) { yc=i; break; }
    dfs1(yc,yc,0); dfs2(yc,yc);
    for(int i=1;i<=m;i++)
       { scanf("%d %d",&x,&y); printf("%d
",lca(x,y)); }
    return 0;
}
原文地址:https://www.cnblogs.com/wuhu-JJJ/p/13511490.html