codevs 1503 愚蠢的宠物

题目描述 Description

大家都知道,sheep有两只可爱的宠物(一只叫神牛,一只叫神菜)。有一天,sheep带着两只宠物到狗狗家时,这两只可爱的宠物竟然迷路了……

狗狗的家因为常常遭到猫猫的攻击,所以不得不把家里前院的路修得非常复杂。狗狗家前院有N个连通的分叉结点,且只有N-1条路连接这N个节点,节点的编号是1-N(1为根节点)。sheep的宠物非常笨,他们只会向前走,不会退后(只向双亲节点走),sheep想知道他们最早什么时候会相遇(即步数最少)。

输入描述 Input Description

第1行:一个正整数N,表示节点个数。

第2~N行:两个非负整数A和B,表示A是B的双亲。(保证A,B<=n)

第N+1行:两个非负整数A和B,表示两只宠物所在节点的位置。(保证A,B<=n)

输出描述 Output Description

输出他们最早相遇的节点号。

样例输入 Sample Input

10
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
4 10
3 6

样例输出 Sample Output

1


【分析】
N个节点,N-1条边,那就是树了…
题目意思就是要找最近公共祖先,裸啊。
倍增法求LCA,不过数据太水,暴力遍历也可以…
我预处理的时间就够暴力做的了…我想我应该是脑子坏掉了。
主要还是让大家看倍增求LCA。


【代码】

//codevs 1503 stupid pet
#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
vector <int> f[1000001];
int fa[1000001][26];
int dep[1000001];
int n,s,e;
bool vis[1000001];
bool flag=0;
inline void dfs(int u,int father,int p)
{
    int i,j;
    if(flag) return;
    if(fa[u][0]==0) dep[u]=0;
    else dep[u]=dep[father]+1;
    if(u==p)
    {
        flag=1;
        return;
    }
    int l=f[u].size()-1;
    fo(i,0,l)
    {
        int v=f[u][i];
        dfs(v,u,p);
    } 
}
inline int lca(int x,int y)
{
    int i,j,k;
    fo(i,1,n)
      fo(j,1,25)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    if(dep[x]<dep[y])
    {
        int tmp=x;
        x=y;
        y=tmp;
    }
    for(i=25;i>=0;i--)
      if(dep[y]<=dep[x]-(1<<i))
        x=fa[x][i];
    if(x==y) return x;
    for(i=25;i>=0;i--)
      if(fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
    int m=0,i,j,k,x,y;
    scanf("%d",&n);
    fo(i,1,n-1)
    {
        scanf("%d%d",&y,&x);
        fa[x][0]=y;
        f[y].push_back(x);
        vis[x]=1;
    }
    scanf("%d%d",&s,&e);
    fo(i,1,n)
      if(!vis[i]) break;
    flag=0;
    dfs(i,0,s);
    flag=0;
    dfs(i,0,e);
    printf("%d\n",lca(s,e));
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值