zoukankan      html  css  js  c++  java
  • 9018:1892:最近公共祖先用LCA来做

    题目描述

    编写一个程序,查找一棵含有n个节点的树中m组两个不同节点的最近公共祖先。

    输入

    第一行两个整数n和q,为树上节点的数目和查询数。节点标号为整数 1,2,...,n。之后n-1行每一行包含一对整数,代表边——第一个整数是第二个整数的父节点。请注意,一个具有n个节点的树有n-1条边。之后q行查询,每行两个整数,表示要查询的两个节点的标号。(输入保证有且只有一棵树)

    输出

    q行,每行一个整数,为此次查询的最近公共祖先的标号

    样例输入

    5 6
    2 5
    2 3
    5 1
    1 4
    1 3
    2 3
    5 4
    1 5
    4 5
    5 4

    样例输出

    2
    2
    5
    5
    5
    5
    

    提示

    2<=n,m<=5*10^5

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    const int INF=500010;
    vector <int> g[INF];
    int fa[40][INF]={0};
    queue <int>q;
    int dep[INF];
    bool use[INF]={false};
    int root;
    int n,m;
    void bfs(int u){//使用的数
      use[u]=true;q.push(u);//将u入队
      while(!q.empty()){//当队伍非空时,深搜
        u=q.front();//取出队首
        for(int i=0;i<g[u].size();i++){//找这根链表的长度,从0到结束
          int v=g[u][i];//v现在是这条链表的第i个
          if(!use[v]){//如果没有使用过
            dep[v]=dep[u]+1;//深度加一
            q.push(v);//将其入队
          }
        }     
        q.pop();//将队尾入队
      }
    }
    void bz(){//倍增
      for(int j=1;j<=30;j++)//不清楚哦。。。。
      for(int i=1;i<=n;i++)
      fa[j][i]=fa[j-1][fa[j-1][i]];
    }
    int LCA(int u,int v){
      if(dep[u]<dep[v])swap(u,v);//保证u为深度较深的
      int dc=dep[u]-dep[v];//求出其差距,u要跳多少
      for(int i=0;i<30;i++)//不超过2的30次方
        if((1<<i)&dc)//如果2的i次方和dc的差二进制第一位为1
          u=fa[i][u];//则u往上移2^i位。
      if(v==u)return u;//如果深度相同,返回
      for(int i=29;i>=0;i--){//
        if(fa[i][u]!=fa[i][v]){//如果跳2的i次方步深度不同,就跳,否则就不跳
          u=fa[i][u];//
          v=fa[i][v];//
        }
      }
      u=fa[0][u];//
      return u;//
    }
    int main(){

      cin>>n>>m;   

      for(int i=1;i<=n;i++)g[i].clear();//清空 

      for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);//输入每次的子节点和父节点
        g[a].push_back(b);//建树,将b放到a内;
        fa[0][b]=a;//父节点
        if(fa[0][a]==0)root=a;//他没有父节点,他为根
      }
      dep[root]=1;//根的深度为1,之后深度搜索
      bfs(root);//深搜;
      bz();//树上倍增,处理fa数组
      int x,y;
      for(int k=1;k<=m;k++){
        scanf("%d%d",&x,&y);//不能用cin
        printf("%d ",LCA(x,y));//不能用cout
      }
    }

    总结

    千万不能用cin和cout,简直是可怕到了极点,还是用scanf和printf比较好

  • 相关阅读:
    在centOS上安装oracle出现java.lang.NoClassDefFoundError问题及解决方法
    centos6.5下安装oracle11g
    配置单点登录
    CentOS 环境变量编辑、保存、立即生效的方法
    python如何调用C语言程序
    python生成exe可执行程序
    python的encode()和decode()函数
    python 获取时间
    python修改字符串的值
    python enumerate()函数
  • 原文地址:https://www.cnblogs.com/linzeli/p/6711069.html
Copyright © 2011-2022 走看看