HDU - 4547 CD操作 (LCA倍增)
阿新 • • 發佈:2018-09-22
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倍增)