Hdu 4547 CD操作 LCA问题

CD操作

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


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问题,码略挫

----------------

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;

const int maxn=411111;

char name_x[1111];
char name_y[1111];
map<string,int>mp;

struct ANS{
    int x;
    int y;
    int lca;
}ans[maxn];

int p[maxn];
int head[maxn];
int qhead[maxn];
struct NODE{
    int to;
    int next;
    int num;
    int lca;
};
NODE edges[maxn];
NODE qedges[maxn];
int edge,qedge;

void addedge(int u,int v)
{
    edges[edge].to=v;edges[edge].next=head[u];head[u]=edge++;
}
void addqedge(int u,int v,int num)
{
    qedges[qedge].num=num;
    qedges[qedge].to=v;qedges[qedge].next=qhead[u];qhead[u]=qedge++;
}

int find(int x)
{
    if (p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

bool visit[maxn];

void LCA(int u)
{
    p[u]=u;
    int k;
    visit[u]=true;
    for (k=head[u];k!=-1;k=edges[k].next)
    {
        if (!visit[edges[k].to])
        {
            LCA(edges[k].to);
            p[edges[k].to]=u;
        }
    }
    for (k=qhead[u];k!=-1;k=qedges[k].next)
    {
        if (visit[qedges[k].to])
        {
            qedges[k].lca=find(qedges[k].to);
            qedges[k^1].lca=qedges[k].lca;
            //cerr<<qedges[k].lca<<"---lca---"<<qedges[k].num<<endl;
            ans[qedges[k].num].lca=qedges[k].lca;
        }
    }
}

int ind[maxn];

int dep[maxn];
void dfs(int u,int pat,int deep)
{
    int k;
    dep[u]=deep;
    for (k=head[u];k!=-1;k=edges[k].next)
    {
        if (edges[k].to!=pat)
        dfs(edges[k].to,u,deep+1);
    }
}

int main()
{
    int T,n,m;
    int x,y;
    int cnt;
    int root;
    scanf("%d",&T);
    while (T--)
    {
        //初始化
        memset(head,-1,sizeof(head));
        memset(qhead,-1,sizeof(qhead));
        memset(edges,0,sizeof(edges));
        memset(qedges,0,sizeof(qedges));
        memset(ind,0,sizeof(ind));
        memset(dep,0,sizeof(dep));
        memset(visit,0,sizeof(visit));
        mp.clear();
        edge=0;
        qedge=0;
        cnt=1;
        //读入数据
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n-1;i++)
        {
            scanf("%s%s",name_x,name_y);
            //映射
            if (mp[name_x]==0)
            {
                x=cnt;
                mp[name_x]=cnt++;
            }
            else
            {
                x=mp[name_x];
            }
            if (mp[name_y]==0)
            {
                y=cnt;
                mp[name_y]=cnt++;
            }
            else
            {
                y=mp[name_y];
            }
            //cerr<<"x y "<<x<<" "<<y<<endl;
            //添加边
            addedge(y,x);
            addedge(x,y);
            //计算入度
            ind[x]++;
        }
        //寻找根节点
        root=0;
        for (int i=1;i<cnt;i++)
        {
            if (ind[i]==0)
            {
                root=i;
            }
        }
        //cerr<<root<<"root"<<endl;
        //读入待处理数据
        for (int i=1;i<=m;i++)
        {
            scanf("%s%s",name_x,name_y);
            x=mp[name_x];
            y=mp[name_y];
            //添加正反询问边
            addqedge(x,y,i);
            addqedge(y,x,i);
            ans[i].x=x;
            ans[i].y=y;
        }
        //寻找lca
        //cerr<<"aaaaaaaaaaaaaaaa"<<endl;
        LCA(root);
        //计算深度
        dfs(root,-1,1);
        //for (int i=1;i<=n;i++) cerr<<dep[i]<<endl;
        //处理询问
        //cerr<<"aaaaaaaaaaaaaaaa"<<endl;
        for (int i=1;i<=m;i++)
        {
            int as=0;
            as=dep[ans[i].x]-dep[ans[i].lca];
            if (ans[i].lca!=ans[i].y) as++;
            if (ans[i].x==ans[i].y) as=0;
            printf("%d\n",as);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值