zoukankan      html  css  js  c++  java
  • [模板] LCA-最近公共祖先-倍增法

    2019-11-07 09:25:45

    C.树之呼吸-叁之型-树上两点路径长度
    Time Limit: 1000 MS Memory Limit: 32768 K
    Total Submit: 7 (4 users) Total Accepted: 2 (2 users) Special Judge: No
    Description

    给一棵 n 个结点的树,结点编号从 1 到 n,并指定 m 号结点为根;

    给出 q 个询问,每次询问从编号为 x 的结点到编号为 y 的结点的路径长度。

    Input

    输入第一行为一个正整数 T,表示测试数据组数;

    对于每组测试数据,输入第一行为三个正整数 n、m、q,表示树的结点数,根结点的编号以及询问数;

    接下来 n - 1 行给出树的结构,每行两个正整数 x、y,表示结点 x 与结点 y 有边相连;

    接下来 q 行给出询问,每行两个正整数 x、y,表示询问从结点 x 到结点 y 的路径长度;

    1 <= T <= 20,1 <= n,q <= 1e5,1 <= m <= n。

    Output

    每组测试数据的第一行输出“Case #i:”(不含引号),表示是第 i 组测试数据;

    接下来 q 行,每行输出一个整数,表示给出的两结点间的路径长路。

    Sample Input
    2
    5 2 3
    1 4
    5 4
    2 4
    3 2
    1 3
    5 2
    4 1
    3 1 2
    1 2
    1 3
    1 1
    2 3
    Sample Output
    Case #1:
    3
    2
    1
    Case #2:
    0
    2
    Author
    陈鑫

    最近公共祖先LCA模板题,

    ans=deep[x]-deep[LCA(x,y)]+deep[y]-deep[LCA(x,y)];

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int amn=2e5+5;
     4 vector<int> eg[amn];
     5 int n,m,maxh,deep[amn],anc[amn][20];    ///maxh为树的最大深度=(int)log2(n)+1,deep为结点的深度,anc为距离结点x路径长度为2^i的结点是哪个
     6 queue<int> q;
     7 
     8 void bfs(int rt){
     9     q.push(rt);deep[rt]=1;
    10     while(q.size()){
    11         int u=q.front();q.pop();
    12         for(int i=0;i<eg[u].size();i++){
    13             int v=eg[u][i];
    14             if(deep[v])continue;
    15             deep[v]=deep[u]+1;      ///深度
    16             anc[v][0]=u;
    17             for(int j=1;j<=maxh;j++) anc[v][j]=anc[anc[v][j-1]][j-1];   ///预处理2^k距离
    18             q.push(v);
    19         }
    20     }
    21 }
    22 int Lca(int x,int y){
    23     if(deep[x]<deep[y])swap(x,y);   ///我们规定x的深度要比y的深度大,所有若x的深度比y的深度小则要将他们交换
    24     for(int i=maxh;i>=0;i--) if(deep[anc[x][i]]>=deep[y])x=anc[x][i];   ///将x和y移到同一深度,为什么是>=,因为anc[x][i]表示距离x结点2^i路径长度的结点时哪个,如果时anc[x][0]则表示距离x结点路径长度为1的结点
    25     if(x==y)return x;   ///如果x==y说明y是他们的LCA,现在x==y了,可以任意返回x或y,这里你返回y也行
    26     for(int i=maxh;i>=0;i--) if(anc[x][i]!=anc[y][i]){x=anc[x][i];y=anc[y][i];} ///找x和y的LCA
    27     return anc[x][0];   ///输出LCA
    28 }
    29 void init(int rt){
    30     memset(deep,0,sizeof deep);
    31     memset(anc,0,sizeof anc);
    32     maxh=(int)log2(n)+1;
    33     bfs(rt);
    34 }
    35 int main(){
    36     int T,Case=1,an,x,y,q;scanf("%d",&T);
    37     while(T--){
    38         for(int i=1;i<=n;i++)eg[i].clear(); ///用vector存边要加这句
    39         scanf("%d%d%d",&n,&m,&q);
    40         for(int i=1;i<n;i++){
    41             scanf("%d%d",&x,&y);
    42             eg[x].push_back(y);
    43             eg[y].push_back(x);
    44         }
    45         init(m);
    46         printf("Case #%d:
    ",Case++);
    47         while(q--){
    48             scanf("%d%d",&x,&y);
    49             an=Lca(x,y);
    50             printf("%d
    ",deep[x]+deep[y]-2*deep[an]);  ///(deep[x]-deep[an])+(deep[y]-deep[an]),x到最近公共祖先的深度+y到最近公共祖先的深度
    51         }
    52     }
    53 }
    54 /**
    55 题意: 给一棵 n 个结点的树,结点编号从 1 到 n,并指定 m 号结点为根;
    56 给出 q 个询问,每次询问从编号为 x 的结点到编号为 y 的结点的路径长度。
    57 思路:求出x和y的最近公共祖先,答案是x到最近公共祖先的深度+y到最近公共祖先的深度
    58 **/
  • 相关阅读:
    Linux软件安装
    虚拟地址和物理地址
    python 读写txt文件
    python 浮点数保留几位小数
    Contiki源码结构
    Contiki Rtimer 模块
    Contiki Ctimer模块
    Contiki Etimer 模块
    Contiki Timer & Stimer 模块
    Contiki clock模块
  • 原文地址:https://www.cnblogs.com/Railgun000/p/11810059.html
Copyright © 2011-2022 走看看