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 就是他们的最近公共祖先。

  • 相关阅读:
    .NET实现Excel文件的读写 未测试
    权限管理设计
    struts1中配置应用
    POJ 2139 Six Degrees of Cowvin Bacon(floyd)
    POJ 1751 Highways
    POJ 1698 Alice's Chance
    POJ 1018 Communication System
    POJ 1050 To the Max
    POJ 1002 4873279
    POJ 3084 Panic Room
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/poj1330_2.html
Copyright © 2011-2022 走看看