0


P10289 [GESP样题 八级] 小杨的旅游

Description

给定一棵

  1. n
  2. n
  3. n 个点的树,每条边权值均为
  4. 1
  5. 1
  6. 1,树上有
  7. k
  8. k
  9. k 个关键点,关键点们在
  10. 0
  11. 0
  12. 0 的时间内相互可达,
  13. q
  14. q
  15. q 次询问,求
  16. s
  17. t
  18. s\to t
  19. st 的最短路。

Analysis

考虑暴力建图,则图上共有

  1. (
  2. n
  3. 1
  4. +
  5. n
  6. (
  7. n
  8. 1
  9. )
  10. 2
  11. )
  12. (n-1+\frac{n(n-1)}{2})
  13. (n1+2n(n1)​)条边,在
  14. n
  15. ,
  16. k
  17. n,k
  18. n,k 均为最大的情况下,图上共有大约
  19. 2
  20. ×
  21. 1
  22. 0
  23. 10
  24. 2 \times 10^{10}
  25. 2×1010 条边,铁定
  1. MLE

我们注意到,从

  1. s
  2. s
  3. s
  4. t
  5. t
  6. t 只有两种情况:
  • 老老实实从树上走;
  • 从 s s s 走到一个关键点 k 1 k_1 k1​,穿越到另一个关键点 k 2 k_2 k2​,再走到 t t t。

第一种情况就是常规树上两点最短路。
第二种情况,根据贪心思想,选取的

  1. k
  2. 1
  3. ,
  4. k
  5. 2
  6. k_1,k_2
  7. k1​,k2 一定是距离
  8. s
  9. ,
  10. t
  11. s,t
  12. s,t 最近的两个。所以我们初始时一次
  1. bfs

求出每个点

  1. i
  2. i
  3. i 到传送门的距离
  4. d
  5. s
  6. t
  7. i
  8. dst_i
  9. dsti​,最终答案即为
  10. d
  11. s
  12. t
  13. s
  14. +
  15. d
  16. s
  17. t
  18. t
  19. dst_s+dst_t
  20. dsts​+dstt​。

Code

  1. // Problem: P10289 [GESP样题 八级] 小杨的旅游// Contest: Luogu// URL: https://www.luogu.com.cn/problem/P10289// Memory Limit: 512 MB// Time Limit: 1000 ms// // Powered by CP Editor (https://cpeditor.org)#include<iostream>#include<queue>#include<cmath>usingnamespace std;using Graph = vector<vector<int>>;constint INF =1e9;structLCA{int n, k;
  2. vector<int> dep;
  3. vector<vector<int>> f;
  4. Graph G;LCA(){}LCA(const Graph &tree):G(tree){
  5. n = G.size();
  6. k =(int)log2(n)+1;
  7. dep.assign(n,0);
  8. f.assign(n,vector<int>(k,-1));dfs(0,0);}voiddfs(int u,int fa){
  9. dep[u]= dep[fa]+1;
  10. f[u][0]= fa;for(int i =1; i < k; i++) f[u][i]= f[f[u][i -1]][i -1];for(auto v: G[u]){if(v == fa)continue;dfs(v, u);}}intlca(int x,int y){if(dep[x]< dep[y])swap(x, y);for(int i = k -1; i >=0; i--)if(dep[f[x][i]]>= dep[y]) x = f[x][i];if(x == y)return x;for(int i = k -1; i >=0; i --)if(f[x][i]!= f[y][i]){
  11. x = f[x][i];
  12. y = f[y][i];}return f[x][0];}intdist(int x,int y){return dep[x]+ dep[y]-2* dep[lca(x, y)];}};signedmain(){
  13. ios::sync_with_stdio(0);
  14. cin.tie(0), cout.tie(0);int n, k, q;
  15. cin >> n >> k >> q;
  16. Graph G(n);for(int i =0, u, v; i < n -1; i++){
  17. cin >> u >> v;
  18. u--, v--;
  19. G[u].push_back(v);
  20. G[v].push_back(u);}
  21. LCA tree(G);
  22. queue<int> que;
  23. vector<int>dis(n, INF);for(int i =0, x; i < k; i++){
  24. cin >> x;
  25. x--;
  26. que.push(x);
  27. dis[x]=0;}while(que.size()){int u = que.front();
  28. que.pop();for(auto v: G[u])if(dis[v]== INF){
  29. dis[v]= dis[u]+1;
  30. que.push(v);}}auto dist =[&](int x,int y){returnmin(tree.dist(x, y), dis[x]+ dis[y]);};for(int i =0, u, v; i < q; i++){
  31. cin >> u >> v;
  32. u--, v--;
  33. cout <<dist(u, v)<< endl;}return0;}
标签: 算法 图论 c++

本文转载自: https://blog.csdn.net/sblsf/article/details/140877273
版权归原作者 pystraf 所有, 如有侵权,请联系我们删除。

“P10289 [GESP样题 八级] 小杨的旅游”的评论:

还没有评论