1. 程式人生 > >HDU - 4547 CD操作 (LCA倍增)

HDU - 4547 CD操作 (LCA倍增)

ems b- lan 傳送門 blank printf .cn spa ret

題目傳送門:HDU - 4547 CD操作

題目大意:

分析:

求出目錄A 到 B所需要的CD操作次數,這裏的A B 位字符串 所以用到map映射,之後直接求LCA分情況討論即可:設求A到B的CD操作數

1、A==B 需要的CD操作數是0

2、A是B的最近公共祖先,則A-->B的CD操作數是0

3、B是A的最近公共祖先,則B-->A的CD操作數是 deep[B]-deep[B]

4、若互相不是最近公共祖先,則CD操作數是 deep[A]-deep[lca(A,B)]+1

#include<iostream>
#include<cstring>
#include
<map> #include<cstdio> using namespace std; const int MAX=100009; const int M=20; int head[MAX],cnt=0; int t,n,m; int up[MAX][M]; int dis[MAX]; int deep[MAX]; char a[50],b[50]; map<string,int>mp; struct Edge{ int next,to,val; }edge[MAX]; inline void add(int u,int v) { edge[cnt].to
=v; edge[cnt].val=1; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int u) //dfs遍歷求出深度 { for(int i=head[u];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==up[u][0])continue; deep[to]=deep[u]+1; up[to][
0]=u; dfs(to); } } void init() { for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) up[i][j]=up[up[i][j-1]][j-1]; } int lca(int a,int b) { if(deep[a]<deep[b])swap(a,b); int d=deep[a]-deep[b]; for(int i=0;i<M;i++) if((1<<i)&d) a=up[a][i]; if(a==b)return a; for(int i=M-1;i>=0;i--) { if(up[a][i]!=up[b][i]) { a=up[a][i];b=up[b][i]; } } return up[a][0]; } int main() { scanf("%d",&t); while(t--) { memset(head,-1,sizeof(head));cnt=0; memset(up,0,sizeof(up)); memset(deep,0,sizeof(deep)); mp.clear(); scanf("%d %d",&n,&m); int count=1; for(int i=0;i<n-1;i++) { scanf("%s %s",a,b); //map將目錄名映射為數字 if(mp[a]==0) mp[a]=count++; if(mp[b]==0) mp[b]=count++; add(mp[b],mp[a]); up[mp[a]][0]=mp[b]; } for(int i=1;i<=n;i++) { if(up[i][0]==0) { dfs(i); break; } } init(); int res; for(int i=0;i<m;i++) { scanf("%s %s",a,b); if(mp[a]==mp[b])res=0; //討論 else if(lca(mp[a],mp[b])==mp[a]) res=1; else if(lca(mp[a],mp[b])==mp[b]) res=deep[mp[a]]-deep[lca(mp[a],mp[b])]; else res=deep[mp[a]]-deep[lca(mp[a],mp[b])]+1; printf("%d\n",res); } } return 0; }

HDU - 4547 CD操作 (LCA倍增)