问从一个目录到另一个目录的最短cd cd..次数
#include<stdio.h> #include<string> #include<map> #include<vector> #include<cmath> #include<stdlib.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; const int N=1e5+10; int n; int E[2*N],R[N]; int t=0; map<string,int> mp; vector<int> vec[N]; bool vis[N]; int now; void rd(int&x){ char ch; for(ch=getchar();ch<'0' || ch>'9';ch=getchar()); x=0; for(;ch>='0' && ch<='9';ch=getchar()) x=x*10+ch-'0'; } void init(){ mp.clear(); for(int i=1;i<=n;i++) vec[i].clear(); memset(vis,0,sizeof vis); } void add(string s1,string s2){ int p1,p2; if(mp.find(s1)==mp.end()) p1=mp[s1]=++now; else p1=mp[s1]; if(mp.find(s2)==mp.end()) p2=mp[s2]=++now; else p2=mp[s2]; vis[p1]=true; vec[p2].push_back(p1); } void dfs(int rt,int dep){//E[i]表示从i个时间点放入的点的深度 R[i]表示点i第一次出现在E数组中的下标,每条边增加两个时间点,一来一回 R[rt]=t; for(int i=0;i<vec[rt].size();i++){ int v=vec[rt][i]; ++t; E[t]=dep+1; dfs(vec[rt][i],dep+1); ++t; E[t]=dep; } } int f[2*N][20]; int col[20]; void build(){ t=0; int root=1; for(int i=1;i<=n;i++) if(!vis[i]){root=i;break;} E[++t]=0; dfs(root,0); col[0]=1;for(int i=1;i<20;i++) col[i]=2*col[i-1]; for(int j=0;j<20;j++) for(int i=1;i+col[j]-1<=2*n-1;i++) if(j==0) f[i][j]=E[i]; else f[i][j]=min(f[i][j-1],f[i+col[j-1]][j-1]); } int solve(int l1,int r1){ int l=R[l1],r=R[r1]; if(l>r) swap(l,r); int k=log(r-l+1)/log(2.0); int res=min(f[l][k],f[r-col[k]+1][k]); int ans=0; if(res!=E[R[r1]]) ans++; ans+=E[R[l1]]-res; return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("aaa","r",stdin); #endif int T; int q; scanf("%d",&T); while(T--){ scanf("%d",&n); scanf("%d",&q); init(); now=0; string s1,s2; for(int i=1;i<n;i++){ cin>>s1>>s2; add(s1,s2); } build(); for(int i=1;i<=q;i++){ cin>>s1>>s2; printf("%d\n",solve(mp[s1],mp[s2])); } } return 0; }