HDU_4547_CD操作(LCA+tarjan)

CD操作

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



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
 
分析:典型LCA问题。先求出每个节点的深度(可以直接在tarjan算法里得到,不需另写dfs函数);然后对于每个查询(u,v),求出其LCA(u,v),再分情况讨论:
1)u == v ;ans = 0;
2)LCA(u,v) == v ;ans = depth[u] - depth[LCA(u,v)] ;
3)LCA(u,v) != v ;ans = depth[u] - depth[LCA(u,v)] + 1 。
顺便吐槽一点,我交C++一直WA,改交G++就AC。不知道HDU在搞什么鬼。

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4547
代码清单:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<string>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxn = 1e5 + 5;
const int maxv = 1e5 + 5;

struct Edge{
    int v,id;
    Edge(){}
    Edge(int v,int id){
        this -> v = v;
        this -> id = id;
    }
};

int T;
int N,M,root;
string name1,name2;
int id,idx1,idx2;
bool hasfa[maxn];
int father[maxn];
map<string,int>idx;
vector<int>graph[maxn];
vector<Edge>edge[maxn];
int color[maxn],ans[maxn],depth[maxn];
pair<int,int>e[maxn];
bool vis[maxn];

int Find(int x){ return x!=father[x] ? father[x]=Find(father[x]) : father[x]; }

int get_idx(string name){
    if(idx.count(name)) return idx[name];
    idx[name]=++id; return id;
}

/*
void get_depth(int u,int dep){
    depth[u]=dep;
    for(int i=0;i<graph[u].size();i++)
        get_depth(graph[u][i],dep+1);
}
*/
void tarjan_LCA(int u){
    color[u]=1; vis[u]=true;
    for(int i=0;i<edge[u].size();i++){
        int ID=edge[u][i].id;
        if(ans[ID]) continue;
        int v=edge[u][i].v;
        if(color[v]==0) continue;
        if(color[v]==1) ans[ID]=v;
        if(color[v]==2) ans[ID]=Find(v);
    }
    for(int i=0;i<graph[u].size();i++){
        int vv=graph[u][i];
        if(!vis[vv]){
            depth[vv]=depth[u]+1;
            tarjan_LCA(vv);
            color[vv]=2;
            father[vv]=u;
        }
    }
}

void init(){
    for(int i=0;i<=maxn;i++){
        graph[i].clear();
        edge[i].clear();
        father[i]=i;
        hasfa[i]=vis[i]=false;
        ans[i]=color[i]=depth[i]=0;
    }
    idx.clear(); id=0; root=0;
}

void input(){
    scanf("%d%d",&N,&M);
    for(int i=1;i<N;i++){
        cin>>name1>>name2;
        idx1=get_idx(name1);
        idx2=get_idx(name2);
        graph[idx2].push_back(idx1);
        hasfa[idx1]=true;
    }
    for(int i=1;i<=M;i++){
        cin>>name1>>name2;
        idx1=get_idx(name1);
        idx2=get_idx(name2);
        e[i].first=idx1;
        e[i].second=idx2;
        edge[idx1].push_back(Edge(idx2,i));
        edge[idx2].push_back(Edge(idx1,i));
    }
}

void solve(){
    for(int i=1;i<=N;i++){ if(!hasfa[i]){ root=i; break; } }
    tarjan_LCA(root);
    for(int i=1;i<=M;i++){
        int sum=depth[e[i].first]-depth[ans[i]];
        if(e[i].second!=ans[i]) sum++;
        if(e[i].first==e[i].second) sum=0;
        printf("%d\n",sum);
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        init();
        input();
        solve();
    }return 0;
}



你可能感兴趣的:(Algorithm,ACM,LCA,Tarjan,hihoCoder)