题目

给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。

输入格式

输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问

输出格式

输出Q行,每行一个整数表示询问的答案

输入样例

9 10 2

1 2 1

1 4 1

3 4 1

2 3 1

3 7 1

7 8 2

7 9 2

1 5 3

1 6 4

5 6 1

1 9

5 7

输出样例

5

6

提示

对于100%的数据,N<=10000,Q<=10000

题解

仙人掌的题目,都与树上的方法相联系,再考虑环的影响

首先如果在树上,我们设d[u]表示u到根的距离,两点u,v的距离dis=d[u]+d[v]−2∗d[lca]

现在加上几个环,我们先跑一遍dfs找出所有的环以及算出d[],然后重构树,将环上的点全部连到该环最高点上,距离为环上到最高点的最短路

这样子构建出来的树,我们可以用倍增套用树的方法求解

如果求解时两点倍增时算得的最后祖先属于同一个环,那么就考虑环的贡献

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #define LL long long int
  7. #define REP(i,n) for (int i = 1; i <= (n); i++)
  8. #define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
  9. using namespace std;
  10. const int maxn = 10005,maxm = 100005,INF = 1000000000;
  11. inline int RD(){
  12. int out = 0,flag = 1; char c = getchar();
  13. while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
  14. while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
  15. return out * flag;
  16. }
  17. int N,M,Q,h[maxn],ne = 2;
  18. struct EDGE{int to,nxt,w;}ed[maxm];
  19. inline void build(int u,int v,int w){
  20. ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
  21. ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
  22. }
  23. int h2[maxn];
  24. struct E{int to,nxt;}e[2 * maxn];
  25. inline void add(int u,int v){e[ne] = (E){v,h2[u]}; h2[u] = ne++;}
  26. int dfn[maxn],low[maxn],d[maxn],dep[maxn],cnt = 0;
  27. int fa[maxn][20],dis[maxn][20];
  28. int cir[maxn],siz[maxn];
  29. void getcir(int rt,int k){
  30. int to = ed[k].to,len = d[to] - d[rt] + ed[k].w;
  31. siz[++siz[0]] = len;
  32. for (int i = to; i != rt; i = fa[i][0]){
  33. add(rt,i);
  34. dis[i][0] = min(d[i] - d[rt],len - d[i] + d[rt]);
  35. cir[i] = siz[0];
  36. }
  37. }
  38. void dfs(int u){
  39. dfn[u] = low[u] = ++cnt; int to;
  40. Redge(u) if ((to = ed[k].to) != fa[u][0]){
  41. if (!dfn[to]){
  42. fa[to][0] = u;
  43. d[to] = d[u] + ed[k].w;
  44. dfs(to);
  45. low[u] = min(low[u],low[to]);
  46. }else low[u] = min(low[u],dfn[to]);
  47. if (dfn[u] < low[to]) add(u,to),dis[to][0] = ed[k].w;
  48. }
  49. Redge(u) if (fa[to = ed[k].to][0] != u && dfn[u] < dfn[to])
  50. getcir(u,k);
  51. }
  52. void dfs2(int u){
  53. REP(i,15){
  54. fa[u][i] = fa[fa[u][i - 1]][i - 1];
  55. dis[u][i] = dis[u][i - 1] + dis[fa[u][i - 1]][i - 1];
  56. }
  57. for (int k = h2[u],to; k; k = e[k].nxt){
  58. fa[to = e[k].to][0] = u; dep[to] = dep[u] + 1;
  59. dfs2(to);
  60. }
  61. }
  62. int solve(int u,int v){
  63. if (dep[u] < dep[v]) swap(u,v);
  64. int ans = 0,D = dep[u] - dep[v];
  65. for (int i = 0; (1 << i) <= D; i++)
  66. if ((1 << i) & D) ans += dis[u][i],u = fa[u][i];
  67. if (u == v) return ans;
  68. for (int i = 15; i >= 0; i--)
  69. if (fa[u][i] != fa[v][i]){
  70. ans += dis[u][i] + dis[v][i];
  71. u = fa[u][i]; v = fa[v][i];
  72. }
  73. if (cir[u] && cir[u] == cir[v])
  74. ans += min(abs(d[u] - d[v]),siz[cir[u]] - abs(d[u] - d[v]));
  75. else ans += dis[u][0] + dis[v][0];
  76. return ans;
  77. }
  78. int main(){
  79. N = RD(); M = RD(); Q = RD(); int a,b,w;
  80. while (M--) a = RD(),b = RD(),w = RD(),build(a,b,w);
  81. ne = 1;
  82. dfs(1);
  83. dep[1] = 1;
  84. dfs2(1);
  85. while (Q--){
  86. a = RD(); b = RD();
  87. printf("%d\n",solve(a,b));
  88. }
  89. return 0;
  90. }

BZOJ2125 最短路 【仙人掌最短路】的更多相关文章

  1. BZOJ.2125.最短路(仙人掌 最短路Dijkstra)

    题目链接 多次询问求仙人掌上两点间的最短路径. 如果是在树上,那么求LCA就可以了. 先做着,看看能不能把它弄成树. 把仙人掌看作一个图(实际上就是),求一遍根节点到每个点的最短路dis[i]. 对于 ...

  2. poj 3463 Sightseeing( 最短路与次短路)

    http://poj.org/problem?id=3463 Sightseeing Time Limit: 2000MS   Memory Limit: 65536K Total Submissio ...

  3. 最短路和次短路问题,dijkstra算法

    /*  *题目大意:  *在一个有向图中,求从s到t两个点之间的最短路和比最短路长1的次短路的条数之和;  *  *算法思想:  *用A*求第K短路,目测会超时,直接在dijkstra算法上求次短路; ...

  4. UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

    最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同 ...

  5. POJ---3463 Sightseeing 记录最短路和次短路的条数

    Sightseeing Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9247   Accepted: 3242 Descr ...

  6. hdu1688(dijkstra求最短路和次短路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1688 题意:第k短路,这里要求的是第1短路(即最短路),第2短路(即次短路),以及路径条数,最后如果最 ...

  7. CF 672C 两个人捡瓶子 最短路与次短路思想

    C. Recycling Bottles time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  8. POJ 3463 Sightseeing 【最短路与次短路】

    题目 Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the ...

  9. POJ - 3463 Sightseeing 最短路计数+次短路计数

    F - Sightseeing 传送门: POJ - 3463 分析 一句话题意:给你一个有向图,可能有重边,让你求从s到t最短路的条数,如果次短路的长度比最短路的长度多1,那么在加上次短路的条数. ...

随机推荐

  1. JS - 兼容的事件助手

    (function () { // 兼容的事件助手 window.CompatibleEventHelper = { addEventListener: function (elem, type, c ...

  2. php学习【2】

    1:运算符 <?php $x=1; echo 1+1;//算术运算符 echo $x+=5;//赋值运算符 echo "<br/>"; echo $x++; ec ...

  3. Windows下安装Python数据库模块--MySQLdb

    ## 1.下载MySQLdb [去官网](http://pypi.python.org/pypi/MySQL-python/) 下载对应的编译好的版本(现在官网最新版本为1.2.5): MySQL-p ...

  4. 尺取法 poj 2566

    尺取法:顾名思义就是像尺子一样一段一段去取,保存每次的选取区间的左右端点.然后一直推进 解决问题的思路: 先移动右端点 ,右端点推进的时候一般是加 然后推进左端点,左端点一般是减 poj 2566 题 ...

  5. Kali2017 Metasploit连接postgresql数据库

    msfdb:msf数据库管理命令 1.查看msf数据库连接状态 msf > db_status [*] postgresql selected, no connection //未连接 2.ms ...

  6. CSS3实现带阴影的弹球

    实现div上下跳动时,底部阴影随着变化 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  7. java跨服务器请求url获得数据

    在项目中,有时需要通过请求远程服务器上的url获取数据(前提是程序所在服务器可以和url服务器ping成功), 用java在后台发送请求时,用到了java.net.URL, java.net.URLC ...

  8. gettid 和pthread_self的区别

    转: Linux中,每个进程有一个pid,类型pid_t,由getpid()取得.Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库 ...

  9. 怎么用 copy 关键字?

    NSString.NSArray.NSDictionary等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString.NSMutableArray.NSMutableDic ...

  10. thinkphp3.1.3验证码优化

    现状 thinkphp3.1.3版本中的验证码字符分布不均匀,在自定义宽高时很明显. 调用代码: Image::buildImageVerify(6, 5, 'png', 150, 50); 生成的验 ...