• HDU4008 Parent and son


      HDU4008 Parent and son

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
    Total Submission(s): 1035    Accepted Submission(s): 249


    Problem Description
    Give you a tree with N vertices and N‐ 1 edges, and then ask you Q queries on “which vertex is Y's son that has the smallest number and which vertex is Y’s descendants that has the smallest number if we choose X as the root of the entire tree?”
     

    Input
    The first line of input is an integer T (T<=10) means the case number. 
    The first line of each test case contains N(2 ≤ N ≤ 100,000) and Q(1 ≤ Q ≤ 100,000). 
    Each of the following N ‐ 1 lines of the test case contains two integers a(1 ≤ a ≤ N) and b(1 ≤ b ≤ N) indicating an edge between a and b. 
    Each of the following Q lines of the test case contains two integers X(1 ≤ X ≤ N) and Y(1 ≤ Y ≤ N, Y ≠ X) indicating an query. 
     

    Output
    For each query, output the Y's son which has the smallest number and Y's descendant that has the smallest number if X is the root of the entire tree. If Y has no sons then output “no answers!”. There is an empty line after each case.
     

    Sample Input
    1 7 3 1 2 1 5 2 3 2 4 5 6 5 7 1 2 5 3 3 2
     

    Sample Output
    3 3 no answers! 1 1
     

    Source
     
    **************************************************************
    题目大意:给你一棵树,这个树的根节点不定。然后有Q次询问。对于每次询问,给定x和y。即当整棵树以x为根的时候,求y的所有儿子中最小的那个编号值以及y的所有
    子孙中最小的编号值。
    解题思路:http://blog.csdn.net/hqd_acm/article/details/6750163我主要是参考了一篇文章,思路是他的,实现是我的。
    还有不得不说的神乎其神的dfn时间戳数组。初识dfn数组是在前几天的图的连通性问题中见识到,当时觉得一个时间戳竟然如此好用。今天更感其神啊。当dfs一棵树的时候,
    我们可以递归得到一个节点他是所有子孙中的最大的时间戳,把这个也记录下来。然后奇迹啊!我们可以在o(1)的时间内判断y是不是在x的子树下面。
    其他的看那篇博客就好了。
    本人代码附上:
    #include <stdio.h>
    #include <string.h>
    #include <vector>
    #include <algorithm>
    #define MIN(a,b) ((a)<(b)?(a):(b))
    #define MAX(a,b) ((a)>(b)?(a):(b))
    #define INF 0x3f3f3f3f
    #define N 100005
    using namespace std;
    
    vector<int>gra[N],ht;
    int mindown[N],fa[N],minson[N][2],dfn[N],now,maxdfn[N];
    int n,m;
    /*mindown数组用来储存每个节点以下最小的子孙的值,fa数组储存每个节点的
    父亲值,minson的两个值分别是每个节点下的最小和次小的儿子值,dfn神乎其神
    的时间戳数组,now用来盖印时间戳,maxdfn数组用来储存每个节点子孙中的最大
    的dfn值*/
    
    void ini(void)//初始化
    {
        memset(fa,0,sizeof(fa));
        memset(dfn,0,sizeof(dfn));
        memset(maxdfn,0,sizeof(maxdfn));
        now=0;
        for(int i=1;i<=n;i++)
            gra[i].clear();
    }
    
    void dfs(int s,int f)//预处理
    {
        fa[s]=f;
        dfn[s]=maxdfn[s]=++now;
        ht.clear();
        mindown[s]=minson[s][0]=minson[s][1]=INF;
        for(int i=0;i<gra[s].size();i++)
            if(!fa[gra[s][i]])
                ht.push_back(gra[s][i]);
        gra[s]=ht;
        for(int i=0;i<gra[s].size();i++)
        {
            int t=gra[s][i];
            dfs(t,s);
            mindown[s]=MIN(mindown[s],t);
            mindown[s]=MIN(mindown[s],mindown[t]);
            if(t<minson[s][0])
                minson[s][1]=minson[s][0],minson[s][0]=t;
            else if(t<minson[s][1])
                minson[s][1]=t;
            maxdfn[s]=MAX(maxdfn[s],maxdfn[t]);
        }
    }
    
    int erfen(int x,int y)//二分查找儿子
    {
        int le=0,ri=gra[y].size(),mid;
        while(1)
        {
            mid=(le+ri)>>1;
            if(dfn[x]>=dfn[gra[y][mid]]&&dfn[x]<=maxdfn[gra[y][mid]])return gra[y][mid];
            if(dfn[x]>maxdfn[gra[y][mid]])le=mid+1;
            if(dfn[x]<dfn[gra[y][mid]])ri=mid-1;
        }
    }
    
    void re(void)//输入
    {
        scanf("%d%d",&n,&m);
        ini();
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            gra[a].push_back(b);
            gra[b].push_back(a);
        }
    }
    
    void run(void)//运行
    {
        dfs(1,-1);
        int temp[2]={INF,INF};//temp表示1节点儿子中mindown的最小值和次小值
        for(int i=0;i<gra[1].size();i++)
        {
            int t=gra[1][i];
            if(mindown[t]<temp[0])
                temp[1]=temp[0],temp[0]=mindown[t];
            else if(mindown[t]<temp[1])
                temp[1]=mindown[t];
        }
        for(int h=1;h<=m;h++)//m次询问
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int fx=-1,fy=-1;
            if(dfn[x]>dfn[y]&&dfn[x]<=maxdfn[y])//在o(1)的时间内知道x是不是y的子孙
                fx=erfen(x,y);
            if(dfn[y]>dfn[x]&&dfn[y]<=maxdfn[x])
                fy=erfen(y,x);
            if(fx==-1)//要么y是x的子孙,要么y和x不在一棵子树上面
            {
                if(mindown[y]==INF)printf("no answers!\n");
                else printf("%d %d\n",minson[y][0],mindown[y]);
            }
            else//x是y的子孙,当y是否等于1的时候有特殊处理
            {
                if(y!=1)
                {
                    if(fx!=minson[y][0])
                        printf("%d %d\n",MIN(minson[y][0],fa[y]),1);
                    else
                    {
                        if(gra[y].size()==1)
                            printf("%d %d\n",fa[y],1);
                        else
                            printf("%d %d\n",MIN(minson[y][1],fa[y]),1);
                    }
                }
                else
                {
                    if(gra[y].size()==1)
                        printf("no answers!\n");
                    else
                    {
                        int a=temp[0];
                        if(a!=INF&&dfn[a]>=dfn[fx]&&dfn[a]<=maxdfn[fx])
                                a=temp[1];
                        int b=minson[1][0];
                        if(fx==minson[1][0])
                            b=minson[1][1];
                        printf("%d %d\n",b,MIN(a,b));
                    }
                }
            }
        }
        puts("");
    }
    
    int main()
    {
        int ncase;
        scanf("%d",&ncase);
        while(ncase--)
        {
            re();
            run();
        }
    }
    

      

  • 相关阅读:
    java 单例设计模式
    JAVAWEB监听器(二)
    pxe无人值守安装linux机器笔记----摘抄
    Ganglia3.1.7安装与配置(收录)
    Hadoop Sentry 学习
    安装和配置Sentry(收录)
    sqoop 的使用 -20160410
    深度分析如何在Hadoop中控制Map的数量(摘抄)
    CDH,CM下载
    大数据培训班 cloudera公司讲师面对面授课 CCDH CCAH CCP
  • 原文地址:https://www.cnblogs.com/Fatedayt/p/2184396.html
Copyright © 2020-2023  润新知