HDU4547 CD操作(最近公共祖先lca,離線Tarjan,有坑點)
阿新 • • 發佈:2019-02-05
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
思路
題意是中文,很好理解,不過有一些需要注意的地方.
- 從父目錄到任意一個子目錄的距離都是1
- 用一個flag記錄一下詢問是從左到右還是從右到左,有幾種情況
- 左邊是右邊的父親,距離為1
- 右邊是左邊的父親,距離是dis[v]到lca(u,v)
- 其他情況+1
其他就是離線求Tarjan的lca了
程式碼
#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 1000000
#define mem(a,b) memset(a,b,sizeof(a))
const int N=100000+7;
const int M=2*N;
int pre[N],first[N],first2[N],tot,tot2;
bool vis[N];//標記有沒有詢問
int n;
int fa[N],ans[N],cnt;
int vis2[N],dis[N];
map<string,int>mp;
struct edge
{
int v,next;
} e[M];
struct Query
{
int v,next,id,flag;//flag用來標記是從左到右還是從到左
} query[M];
void add_edge(int u,int v)
{
e[tot].v=v;
e[tot].next=first[u];
first[u]=tot++;
}
void add_query(int u,int v,int id,int flag)
{
query[tot2].flag=flag;
query[tot2].id=id;
query[tot2].v=v;
query[tot2].next=first2[u];
first2[u]=tot2++;
}
int find(int x)
{
return x==pre[x]?x:pre[x]=find(pre[x]);
}
void lca(int u,int fa)
{
for(int i=first[u]; ~i; i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
lca(v,u);
pre[v]=u;
}
vis[u]=1;
for(int i=first2[u]; ~i; i=query[i].next)
{
int v=query[i].v;
if(vis[v])
{
int id=query[i].id;
int flag=query[i].flag;
if(flag==1)
{
if(u==find(v))
ans[id]=1;
else if(find(u)==v)
ans[id]=dis[u]-dis[find(v)];
else
ans[id]=dis[u]-dis[find(v)]+1;
}
else
{
int u1=v;
int v1=u;
if(u1==find(v1))
ans[id]=1;
else if(find(u1)==v1)
ans[id]=dis[u1]-dis[find(v)];
else
ans[id]=dis[u1]-dis[find(v)]+1;
}
}
}
}
void dfs(int u,int len)
{
vis2[u]=1;
dis[u]=len;
for(int i=first[u]; ~i; i=e[i].next)
{
int v=e[i].v;
if(!vis2[v])
dfs(v,len+1);
}
}
void init()
{
mem(first,-1);
mem(first2,-1);
mem(vis,0);
mem(vis2,0);
mem(fa,-1);
mem(ans,0);
tot=0;
tot2=0;
cnt=1;
mp.clear();
for(int i=1; i<=n; i++)
pre[i]=i;
}
struct node
{
int u,v;
} zz[N];
int main()
{
int t,m;
string s1,s2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1; i<n; i++)
{
cin>>s1>>s2;
if(!mp[s1]) mp[s1]=cnt++;
if(!mp[s2]) mp[s2]=cnt++;
int a=mp[s1],b=mp[s2];
add_edge(a,b);
add_edge(b,a);
fa[a]=b;
}
int root=1;
while(~fa[root]) root=fa[root];
dfs(root,0);
for(int i=1; i<=m; i++)
{
cin>>s1>>s2;
int a=mp[s1],b=mp[s2];
zz[i].u=a,zz[i].v=b;
add_query(a,b,i,1);
add_query(b,a,i,2);
}
lca(root,root);
for(int i=1; i<=m; i++)
{
int u=zz[i].u,v=zz[i].v;
if(u==v)
puts("0");
else
printf("%d\n",ans[i]);
}
}
return 0;
}