zoukankan      html  css  js  c++  java
  • HDU 4547 CD操作(LCA)

    CD操作

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
    Total Submission(s): 78    Accepted Submission(s): 14


    Problem Description
      在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
      这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
      
      1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
      2. CD .. (返回当前目录的上级目录)
      
      现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
     
    Input
    输入数据第一行包含一个整数T(T<=20),表示样例个数;
    每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
    接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
    最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
    数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
     
    Output
    请输出每次询问的结果,每个查询的输出占一行。
     
    Sample Input
    2 3 1 B A C A B C 3 2 B A C B A C C A
     
    Sample Output
    2 1 2
     
    Source
     
    Recommend
    liuyiding
     
     
     
     
    目录刚好成一颗树。
    树有唯一的根结点。
    每步操作可以到上一级目录,或者直接到下面的目录。
     
    其实就是查询LCA
     
    要求u->v
    把u、v的lca求出来,设为tmp
    那么肯定是先u->tmp->u
     
    u->temp的步数刚好是他们的深度差,一个数组存深度差就可以了。
     
    temp->v如果不相等就是一步,相等就是0步
     
     
    LCA还是不熟悉啊,只会套模板,下次来补
     
    //============================================================================
    // Name        : C.cpp
    // Author      : 
    // Version     :
    // Copyright   : Your copyright notice
    // Description : Hello World in C++, Ansi-style
    //============================================================================
    
    #include <iostream>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <math.h>
    using namespace std;
    
    const int MAXN=100010;
    
    int rmq[2*MAXN];//建立RMQ的数组
    
    //***************************
    //ST算法,里面含有初始化init(n)和query(s,t)函数
    //点的编号从1开始,1-n.返回最小值的下标
    //***************************
    struct ST
    {
        int mm[2*MAXN];//mm[i]表示i的最高位,mm[1]=0,mm[2]=1,mm[3]=1,mm[4]=2
        int dp[MAXN*2][20];
        void init(int n)
        {
            mm[0]=-1;
            for(int i=1;i<=n;i++)
            {
                mm[i]=((i&(i-1))==0?mm[i-1]+1:mm[i-1]);
                dp[i][0]=i;
            }
            for(int j=1;j<=mm[n];j++)
              for(int i=1;i+(1<<j)-1<=n;i++)
                 dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
        int query(int a,int b)//查询a到b间最小值的下标
        {
            if(a>b)swap(a,b);
            int k=mm[b-a+1];
            return rmq[dp[a][k]]<rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
        }
    };
    
    //边的结构体定义
    struct Node
    {
        int to,next;
    };
    
    /* ******************************************
    LCA转化为RMQ的问题
    MAXN为最大结点数。ST的数组 和 F,edge要设置为2*MAXN
    
    F是欧拉序列,rmq是深度序列,P是某点在F中第一次出现的下标
    *********************************************/
    
    struct LCA2RMQ
    {
        int n;//结点个数
        Node edge[2*MAXN];//树的边,因为是建无向边,所以是两倍
        int tol;//边的计数
        int head[MAXN];//头结点
    
        bool vis[MAXN];//访问标记
        int F[2*MAXN];//F是欧拉序列,就是DFS遍历的顺序
        int P[MAXN];//某点在F中第一次出现的位置
        int cnt;
    
        ST st;
        void init(int n)//n为所以点的总个数,可以从0开始,也可以从1开始
        {
            this->n=n;
            tol=0;
            memset(head,-1,sizeof(head));
        }
        void addedge(int a,int b)//加边
        {
            edge[tol].to=b;
            edge[tol].next=head[a];
            head[a]=tol++;
            edge[tol].to=a;
            edge[tol].next=head[b];
            head[b]=tol++;
        }
    
        int query(int a,int b)//传入两个节点,返回他们的LCA编号
        {
            return F[st.query(P[a],P[b])];
        }
    
        void dfs(int a,int lev)
        {
            vis[a]=true;
            ++cnt;//先加,保证F序列和rmq序列从1开始
            F[cnt]=a;//欧拉序列,编号从1开始,共2*n-1个元素
            rmq[cnt]=lev;//rmq数组是深度序列
            P[a]=cnt;
            for(int i=head[a];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                if(vis[v])continue;
                dfs(v,lev+1);
                ++cnt;
                F[cnt]=a;
                rmq[cnt]=lev;
            }
        }
    
        void solve(int root)
        {
            memset(vis,false,sizeof(vis));
            cnt=0;
            dfs(root,0);
            st.init(2*n-1);
        }
    }lca;
    
    bool flag[MAXN];
    map<string,int>mp;
    
    int deep[MAXN];
    vector<int>vec[MAXN];
    void bfs(int root)
    {
        memset(deep,0,sizeof(deep));
        queue<int>q;
        while(!q.empty())q.pop();
        deep[root]=1;
        q.push(root);
        while(!q.empty())
        {
            int tmp=q.front();
            q.pop();
            int sz=vec[tmp].size();
            for(int i=0;i<sz;i++)
            {
                if(deep[vec[tmp][i]]==0)
                {
                    deep[vec[tmp][i]]=deep[tmp]+1;
                    q.push(vec[tmp][i]);
                }
            }
        }
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int T;
        int N,m;
        int u,v;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&N,&m);
            memset(flag,false,sizeof(flag));
            lca.init(N);
            string str1,str2;
            int id=0;
            mp.clear();
            for(int i=1;i<=N;i++)vec[i].clear();
            for(int i=1;i<N;i++)
            {
                cin>>str1>>str2;
                if(mp[str1]==0)mp[str1]=++id;
                if(mp[str2]==0)mp[str2]=++id;
                u=mp[str1];
                v=mp[str2];
                vec[v].push_back(u);
                lca.addedge(v,u);
                flag[u]=true;
            }
            int root;
            for(int i=1;i<=N;i++)
              if(!flag[i])
              {
                  root=i;
                  break;
              }
            //printf("root:%d\n",root);
            lca.solve(root);
            bfs(root);
    
            //for(int i=1;i<=N;i++)printf("%d:%d\n",i,deep[i]);
    
            while(m--)
            {
                cin>>str1>>str2;
                u=mp[str1];
                v=mp[str2];
                int tmp=lca.query(u,v);
                //cout<<str1<<" "<<str2<<endl;
                //printf("%d  %d  %d\n",u,v,tmp);
                int ans=deep[u]-deep[tmp];
                if(tmp!=v)ans++;
                printf("%d\n",ans);
            }
        }
        return 0;
    }
     
     
     
     
     
     
     
    人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想
  • 相关阅读:
    再谈TextField
    IOS-TextField知多少
    leftBarButtonItems
    LeftBarButtonItems,定制导航栏返回按钮
    Apple Mach-O Linker (id) Error "_OBJC_CLASS...错误解决办法 Apple Mach-O Linker (id) Error "_OBJC_CLASS...错误解决办法
    Unrecognized Selector Sent to Instance问题之诱敌深入关门打狗解决办法
    UNRECOGNIZED SELECTOR SENT TO INSTANCE 问题快速定位的方法
    Present ViewController,模态详解
    UILABEL AUTOLAYOUT自动换行 版本区别
    iOS自动布局解决警告Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0
  • 原文地址:https://www.cnblogs.com/kuangbin/p/3084435.html
Copyright © 2011-2022 走看看