[BZOJ1764][USACO MAR11银组]聚会地点

13 篇文章 0 订阅
6 篇文章 0 订阅
题目描述
Bessie和Jon每天都要去他们所居住的小镇的某些地方游玩。有趣的是,他们居住的小镇是一个树的结构,也就意味是,小镇的每个地方之间有且仅有一条通路(不是指一条边,而是指一条通路),每个地方都会有且仅有一个父亲地点(除了小镇的城镇中心,它没有祖先)。
小镇共有N个地点(1 <= N <= 1,000),编号1~N。点1是镇的中心。
Bessie和Jon决定每天都要在游玩后见面,他们见面的地点总是在他们游玩的两个地方之间的那条通路中,离城镇中心最近的地方,下面给出他们的旅行日程,你需要帮他们每天的见面地点。
你可以理解为城镇中心就是成为在这个树结构上的根。
                       地点        它的父亲地点
             [1]           ---------    ----------------
            / | \              1              ---(城镇中心没有父亲)
           /  |  \             2               1
         [2] [3] [6]           3               1
         /        | \          4               2
        /         |  \         5               8
      [4]        [8]  [9]      6               1
                /   \          7               8
               /     \         8               6
             [5]     [7]       9               6
 以下为他们某次见面的安排:
        Bessie      Jon       Meeting Place
             --------    --------     ---------------
                 2           7               1
                 4           2               2
                 1           1               1
                 4           1               1
                 7           5               8
                 9           5               6

输入
第1行:两个数N,M代表一共有N个地方,B和J已经进行了M次见面
第2..N-1行,每行一个数X,代表第i个地点的父亲为X
再接下来M行,每行两个数,分别代表B和J当天准备去游玩的地方
1<=N<=1000,1<=M<=1000

输出
一共M行,每行一个数代表B和J当天见面的地方。
样例输入
9 6
1
1
2
8
1
8
6
6
2 7
4 2
3 3
4 1
7 5
9 5

样例输出
1
2
3
1
8
6


题解:LCA裸题


倍增版:
#include<iostream> 
#include<cstring> 
#include<cstdlib> 
#include<cstdio> 
#include<cmath> 
#include<algorithm> 
using namespace std; 
const int N=1010; 
const int LOG=10; 
  
void Getin( int &shu ) { 
    char c; int f=1; shu=0; 
    for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1; 
    for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0'; 
    shu*=f; 
} 
  
int n, m, p1, p2; 
int fa[N], f[N][15], dep[N]; 
  
void Build() { 
    for( int i=2; i<=n; i++ ) 
        Getin(fa[i]), f[i][0]=fa[i]; 
    for( int j=1; j<=LOG; j++ ) 
        for( int i=1; i<=n; i++ ) 
            f[i][j]=f[ f[i][j-1] ][j-1]; 
} 
    
void Deep() {  
    for( int i=2; i<=n; i++ ) {  
        int t=i;  
        while( t!=1 ) t=fa[t], dep[i]++;  
    }  
}  
  
int getk( int r ,int k ) { 
    for( int i=0; i<=LOG; i++ ) 
        if( k&( 1<<i ) ) r=f[r][i]; 
    return r; 
} 
  
int getd( int r, int d ) { 
    return getk( r, dep[r]-d ); 
} 
  
int LCA_Find() { 
    if( dep[p1]<dep[p2] ) swap( p1, p2 );  
    p1=getd( p1, dep[p2] ); 
    if( p1==p2 ) return p1; 
    for( int i=LOG; i>=0; i-- ) 
        if( f[p1][i]!=f[p2][i] ) 
            p1=f[p1][i], p2=f[p2][i]; 
    return fa[p1]; 
} 
  
int main() { 
    Getin(n); Getin(m); 
    Build(); 
    Deep(); 
    for( int i=1; i<=m; i++ ) { 
        Getin( p1 ); Getin( p2 ); 
        printf( "%d\n", LCA_Find() ); 
    } 
    return 0; 
} 


链剖版:
#include<iostream> 
#include<cstring> 
#include<cstdlib> 
#include<cstdio> 
#include<cmath> 
#include<algorithm> 
using namespace std; 
const int N=1010; 
  
  
int n, m; 
void Getin( int &shu ) { 
    char c; int f=1; shu=0; 
    for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1; 
    for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0'; 
    shu*=f; 
} 
  
int fir[N], ecnt; 
struct nodes{ int e, next; }edge[N<<1]; 
void Link( int s, int e ) { 
    edge[++ecnt].e=e; edge[ecnt].next=fir[s]; fir[s]=ecnt; 
} 
  
  
int fa[N], dep[N], siz[N], son[N]; 
void DFS1( int r, int d ) { 
    dep[r]=d; siz[r]=1; 
    for( int i=fir[r]; i; i=edge[i].next ) { 
        DFS1( edge[i].e, d+1 ); 
        siz[r]+=siz[ edge[i].e ]; 
        if( siz[ edge[i].e ]>siz[ son[r] ] ) son[r]=edge[i].e; 
    } 
} 
  
int top[N]; 
void DFS2( int r ) { 
    if( son[r] ) top[ son[r] ]=top[r], DFS2( son[r] ); 
    for( int i=fir[r]; i; i=edge[i].next ) 
        if( edge[i].e!=son[r] ) { 
            top[ edge[i].e ]=edge[i].e; 
            DFS2( edge[i].e ); 
        } 
} 
  
int p1, p2; 
int LAC() { 
    while( top[p1]!=top[p2] ) { 
        if( dep[ top[p1] ]>dep[ top[p2] ] ) p1=fa[ top[p1] ]; 
        else p2=fa[ top[p2] ]; 
    } 
    return dep[p1]<dep[p2] ? p1 : p2; 
} 
  
  
int main() { 
    Getin(n); Getin(m); 
    for( int i=2; i<=n; i++ ) Getin( fa[i] ), Link( fa[i], i ); 
      
    DFS1( 1, 1 ); 
    top[1]=1; DFS2(1); 
      
    for( int i=1; i<=m; i++ ) { 
        Getin( p1 ); Getin( p2 ); 
        printf( "%d\n", LAC() ); 
    } 
    return 0; 
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值