zoukankan      html  css  js  c++  java
  • [POJ 1330] Nearest Common Ancestors (倍增法)

    题目同上篇,最近公共祖先。

    因为没有清零tot,RE了好多次TAT

    一定要初始化啊!!

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<iostream>
     5 using namespace std;
     6 int root,head[10010];
     7 int next[10010],to[10010],tot;
     8 int deep[10010],n;
     9 int p[10010][16];
    10 int deg[10010];
    11 inline void bfs(int root) {
    12     queue<int> Q;  
    13     p[root][0]=root; deep[root]=0;  
    14     Q.push(root);  
    15     while(!Q.empty()) {  
    16         int u=Q.front(); Q.pop();  
    17         for(int i=1;i<15;i++)  
    18             p[u][i]=p[p[u][i-1]][i-1];  
    19         for(int i=head[u];i!=-1;i=next[i]) {  
    20             int v=to[i];  
    21             deep[v]=deep[u]+1; p[v][0]=u;  
    22             Q.push(v);  
    23         }  
    24     }  
    25 }
    26 inline int LCA(int x,int y) {
    27     if(deep[x]<deep[y]) {int t=x;x=y;y=t;}
    28     for(int i=0;i<15;i++)  
    29         if((deep[x]-deep[y]) & (1<<i)) x=p[x][i];  
    30     if(x==y)  return x;  
    31     for(int i=14;i>=0;i--)  
    32         if(p[x][i]!=p[y][i])  
    33             x=p[x][i],y=p[y][i];  
    34     return p[x][0];  
    35 }
    36 int main() {
    37     int T;
    38     scanf("%d",&T);
    39     while(T--) {
    40         tot=0;
    41         memset(head,-1,sizeof(head)); memset(deg,0,sizeof(deg));
    42         scanf("%d",&n);
    43         for (int i=1;i<=n-1;++i) {
    44             int u,v;
    45             scanf("%d%d",&u,&v);
    46             to[tot]=v;
    47             next[tot]=head[u];
    48             head[u]=tot++;
    49             deg[v]=1; 
    50         }
    51         for (int i=1;i<=n;++i)
    52             if(! deg[i]) {root=i;break;}
    53         bfs(root);
    54         int u,v;
    55         scanf("%d%d",&u,&v);
    56         printf("%d
    ",LCA(u,v));
    57     }
    58     return 0;
    59 }
    View Code

    倍增法简介:

    deep[i] 表示 i节点的深度, fa[i,j]表示 i 的 2^j (即2的j次方) 倍祖先,那么fa[i , 0]即为节点i 的父亲,然后就有一个递推式子fa[i,j]=fa [fa[i,j-1],j-1]

    可以这样理解:设tmp = fa [i, j - 1] ,tmp2 = fa [tmp, j - 1 ] ,即tmp 是i 的第2 ^ (j - 1) 倍祖先,tmp2 是tmp 的第2 ^ (j - 1) 倍祖先,

    所以tmp2 是i 的第2 ^ (j - 1) + 2 ^ (j - 1) =  2^ j 倍祖先

    注意:这里的“倍”可不能理解为倍数的意思,而是距离节点i有多远的意思,节点i的第2 ^ j 倍祖先表示的节点u满足deep[ u ] - deep[ i ] = 2 ^ j。

            这样子一个O(NlogN)的预处理求出每个节点的 2^k 的祖先  
            然后对于每一个询问的点对a, b的最近公共祖先就是: 

     先判断是否 d[x]< d[y] ,如果是的话就交换一下(保证 x 的深度大于 y 的深度), 然后把 x 调到与 y 同深度, 同深度以后再把a, b 同时往上调,调到有一个最小的 j 满足fa [x,j] != fa [y,j] (x,y是在不断更新的), 最后再把(x,y)往上调(x=p[x,0], y=p[y,0])  ,一个一个向上调直到x = y, 这时 x或y 就是他们的最近公共祖先。

  • 相关阅读:
    HashMap 的数据结构
    JVM的内存区域划分
    分库分表的基本思想
    分表与分库使用场景以及设计方式
    千万数据的分库分表(一)
    用c++实现快速排序和归并排序
    如何查看python版本号?
    python的正则表达式
    python3的队列,比python2更好
    markdown如何插入代码?
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/poj1330_2.html
Copyright © 2011-2022 走看看