HDU - 4547 CD操作 (LCA倍增)
Posted ljwcarrot
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 4547 CD操作 (LCA倍增)相关的知识,希望对你有一定的参考价值。
题目传送门: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 ",res); } } return 0; }
以上是关于HDU - 4547 CD操作 (LCA倍增)的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增