题意:在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名...目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
链接:点我
先返回到根目录,然后直接前进到目标目录
目录刚好成一颗树。
树有唯一的根结点。
每步操作可以到上一级目录,或者直接到下面的目录。
其实就是查询LCA
要求u->v
把u、v的lca求出来,设为tmp
那么肯定是先u->tmp->u
u->temp的步数刚好是他们的深度差,一个数组存深度差就可以了。
temp->v如果不相等就是一步,相等就是0步
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <queue> 5 #include <map> 6 #include <vector> 7 #include <math.h> 8 #include <string> 9 #include <stdio.h> 10 #include <math.h> 11 using namespace std; 12 #define MOD 1000000007 13 #define pb(a) push_back(a) 14 const int INF=0x3f3f3f3f; 15 const double eps=1e-5; 16 typedef long long ll; 17 #define cl(a) memset(a,0,sizeof(a)) 18 #define ts printf("***** "); 19 const int MAXN=100010; 20 int n,m,ttt; 21 int a[MAXN]; 22 int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列 23 struct ST 24 { 25 int mm[2*MAXN]; 26 int dp[2*MAXN][20];//最小值对应的下标 27 void init(int n) 28 { 29 mm[0] = -1; 30 for(int i = 1;i <= n;i++) 31 { 32 mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1]; 33 dp[i][0] = i; 34 } 35 for(int j = 1; j <= mm[n];j++) 36 for(int i = 1; i + (1<<j) - 1 <= n; i++) 37 dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; 38 } 39 int query(int a,int b)//查询[a,b]之间最小值的下标 40 { 41 if(a > b)swap(a,b); 42 int k = mm[b-a+1]; 43 return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; 44 } 45 }; 46 //边的结构体定义 47 struct Edge 48 { 49 int to,next; 50 }; 51 Edge edge[MAXN*2]; 52 int tot,head[MAXN]; 53 int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始 54 int P[MAXN];//P[i]表示点i在F中第一次出现的位置 55 int cnt; 56 ST st; 57 void init() 58 { 59 tot = 0; 60 memset(head,-1,sizeof(head)); 61 } 62 void addedge(int u,int v)//加边,无向边需要加两次 63 { 64 edge[tot].to = v; 65 edge[tot].next = head[u]; 66 head[u] = tot++; 67 } 68 void dfs(int u,int pre,int dep) 69 { 70 F[++cnt] = u; 71 rmq[cnt] = dep; 72 P[u] = cnt; 73 for(int i = head[u];i != -1;i = edge[i].next) 74 { 75 int v = edge[i].to; 76 if(v == pre)continue; 77 dfs(v,u,dep+1); 78 F[++cnt] = u; 79 rmq[cnt] = dep; 80 } 81 } 82 void LCA_init(int root,int node_num)//查询LCA前的初始化 83 { 84 cnt = 0; 85 dfs(root,root,0); 86 st.init(2*node_num-1); 87 } 88 int query_lca(int u,int v)//查询u,v的lca编号 89 { 90 return F[st.query(P[u],P[v])]; 91 } 92 bool flag[MAXN]; 93 int Count_num[MAXN]; 94 int deep[MAXN]; 95 vector<int>vc[MAXN]; 96 map<string,int> mp; 97 void bfs(int root) 98 { 99 cl(deep); 100 int now,next; 101 queue<int> q; 102 q.push(root); 103 deep[root]=1; 104 while(!q.empty()) 105 { 106 now=q.front(); 107 q.pop(); 108 for(int i=0;i<vc[now].size();i++) 109 { 110 next=vc[now][i]; 111 if(deep[next]==0) 112 { 113 deep[next]=deep[now]+1; 114 q.push(next); 115 } 116 } 117 118 } 119 } 120 int main() 121 { 122 int i,j,k; 123 #ifndef ONLINE_JUDGE 124 freopen("1.in","r",stdin); 125 #endif 126 scanf("%d",&ttt); 127 int ca=1; 128 while(ttt--) 129 { 130 scanf("%d%d",&n,&m); 131 cl(flag); 132 init(); 133 for(int i=0;i<=n;i++)vc[i].clear(); 134 string u,v; 135 mp.clear(); 136 int tot=0; 137 char s1[5],s2[5]; 138 for(i=0;i<n-1;i++) 139 { 140 cin>>u>>v; 141 if(mp[u]==0) mp[u]=++tot; 142 if(mp[v]==0) mp[v]=++tot; 143 int a1=mp[u]; 144 int a2=mp[v]; 145 vc[a2].pb(a1); 146 addedge(a2,a1); 147 addedge(a1,a2); 148 flag[a1]=1; 149 } 150 int root; 151 for(int i=1;i<=n;i++) 152 if(!flag[i]) 153 { 154 root=i; 155 break; 156 } 157 LCA_init(root,n); 158 bfs(root); 159 for(i=0;i<m;i++) 160 { 161 cin>>u>>v; 162 int a1=mp[u]; 163 int a2=mp[v]; 164 int temp=query_lca(a1,a2); 165 int ans=deep[a1]-deep[temp]; 166 if(temp!=a2) ans++; 167 printf("%d ",ans); 168 } 169 } 170 }