俞鼎力大牛的课件

对于原图以 \(t\) 为根建出任意一棵最短路径树 \(T\),即反着从 \(t\) 跑出到所有点的最短路 \(dis\)

它有一些性质:

性质1:

对于一条 \(s\) 到 \(t\) 的路径的边集 \(P\),去掉 \(P\) 中和 \(T\) 的交集,记为 \(P'\)。

那么 \(P'\) 对于中任意相邻(从 \(s\) 到 \(t\) 的顺序)的两条边 \(e,f\),满足 \(f\) 的起点在 \(T\) 中为 \(e\) 的终点的祖先或者为相同点。

因为 \(P\) 中 \(e,f\) 之间由树边相连或者直接相连。

性质2:

对于不在 \(T\) 中的边 \(e\) ,设 \(u\) 为起点,\(v\) 为终点,\(w\)为权值。

定义 \(\Delta_e=dis_v+w-dis_u\),即选这条边的路径和最短路的长度的差

设 \(L_P\) 表示路径长度,则有

\[L_P=dis_s+\sum_{e\in p'}\Delta_e
\]

这很显然。

性质3:

对于满足性质 \(1\) 的 \(P'\)的定义的边集 \(S\),有且仅有一条 \(s\) 到 \(t\) 的路径的边集 \(P\),使得 \(P'=S\)。

因为树 \(T\) 上的两个点之间有且仅有一条路径。

问题转化

求第 \(k\) 小的满足性质 \(1\) 的 \(P'\)的定义的边集

算法

用小根堆维护边集 \(P\)

初始 \(P\) 为空集(实际上只要维护边集当前尾部的边的起点是哪一个就好了,空集即 \(s\))

每次取出最小权值的边集 \(P\),设当前尾部的边的起点为 \(x\)

有两种方法可以得到一个新的边集:

1.替换 \(x\) 为起点的这条边为一条刚好大于等于它的非树边。

2.尾部接上一条起点为以 \(x\) 为起点的这条边的终点在 \(T\) 中祖先(包括自己)连出去的所有非树边的最小边。

然后就是怎么维护祖先出去的所有非树边的最小边:

显然可以从祖先转移过来,直接可并堆即可。

又因为要保留每个点的信息,所以合并的时候可持久化即可

和线段树合并的可持久化一样,然后就可以过了。

建议可以看一看课件

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. template <class Num> inline void Cmax(Num &x, const Num y) {
  5. x = y > x ? y : x;
  6. }
  7. template <class Num> inline void Cmin(Num &x, const Num y) {
  8. x = y < x ? y : x;
  9. }
  10. const int maxn(5005);
  11. const int maxm(2e5 + 5);
  12. const double eps(1e-8);
  13. int n, m, first[maxn], cnt, vis[maxn], rt[maxn], tot, cov[maxm << 1], ans, fa[maxn];
  14. double se, e, dis[maxn];
  15. priority_queue < pair <double, int> > q;
  16. struct Heap {
  17. int ls, rs, dis, ed;
  18. double w;
  19. } tr[maxm * 20];
  20. struct Edge {
  21. int to, next;
  22. double w;
  23. } edge[maxm << 1];
  24. inline void Add(int u, int v, double w) {
  25. edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
  26. edge[cnt] = (Edge){u, first[v], w}, first[v] = cnt++;
  27. }
  28. inline int NewNode(double w, int ed) {
  29. int x = ++tot;
  30. tr[x].w = w, tr[x].dis = 1, tr[x].ed = ed;
  31. return x;
  32. }
  33. int Merge(int x, int y) {
  34. if (!x || !y) return x + y;
  35. if (tr[x].w - tr[y].w >= eps) swap(x, y);
  36. int p = ++tot;
  37. tr[p] = tr[x], tr[p].rs = Merge(tr[p].rs, y);
  38. if (tr[tr[p].ls].dis < tr[tr[p].rs].dis) swap(tr[p].ls, tr[p].rs);
  39. tr[p].dis = tr[tr[x].rs].dis + 1;
  40. return p;
  41. }
  42. void Dfs(int u) {
  43. vis[u] = 1;
  44. for (int e = first[u], v; e != -1; e = edge[e].next)
  45. if (e & 1) {
  46. double w = edge[e].w;
  47. if (fabs(dis[u] + w - dis[v = edge[e].to]) < eps && !vis[v])
  48. fa[v] = u, cov[e ^ 1] = 1, Dfs(v);
  49. }
  50. }
  51. int main() {
  52. memset(first, -1, sizeof(first));
  53. memset(dis, 127, sizeof(dis));
  54. scanf("%d%d%lf", &n, &m, &se);
  55. for (int i = 1, u, v; i <= m; ++i) scanf("%d%d%lf", &u, &v, &e), Add(u, v, e);
  56. dis[n] = 0, q.push(make_pair(0, n));
  57. while (!q.empty()) {
  58. int u = q.top().second;
  59. q.pop();
  60. if (vis[u]) continue;
  61. vis[u] = 1;
  62. for (int e = first[u]; ~e; e = edge[e].next)
  63. if (e & 1) {
  64. int v = edge[e].to;
  65. if (dis[v] - (dis[u] + edge[e].w) >= eps)
  66. q.push(make_pair(-(dis[v] = dis[u] + edge[e].w), v));
  67. }
  68. }
  69. for (int i = 1; i <= n; ++i) vis[i] = 0;
  70. Dfs(n);
  71. for (int e = 0, u, v; e < cnt; e += 2)
  72. if (!cov[e]) {
  73. u = edge[e ^ 1].to, v = edge[e].to;
  74. if (dis[u] == dis[0] || dis[v] == dis[0]) continue;
  75. rt[u] = Merge(rt[u], NewNode(dis[v] + edge[e].w - dis[u], v));
  76. }
  77. for (int i = 1; i <= n; ++i) q.push(make_pair(-dis[i], i));
  78. for (int i = 1, u; i <= n; ++i) {
  79. u = q.top().second, q.pop();
  80. if (fa[u]) rt[u] = Merge(rt[u], rt[fa[u]]);
  81. }
  82. if (dis[1] - se < eps) se -= dis[1], ++ans;
  83. if (rt[1]) q.push(make_pair(-tr[rt[1]].w, rt[1]));
  84. while (!q.empty()) {
  85. int ed = q.top().second;
  86. double cur = q.top().first, w = dis[1] - cur;
  87. if (w - se >= eps) break;
  88. q.pop(), se -= w, ++ans;
  89. for (int i = 0; i < 2; ++i) {
  90. int nxt = i ? tr[ed].rs : tr[ed].ls;
  91. if (nxt) q.push(make_pair(cur + tr[ed].w - tr[nxt].w, nxt));
  92. }
  93. if (rt[tr[ed].ed]) q.push(make_pair(cur - tr[rt[tr[ed].ed]].w, rt[tr[ed].ed]));
  94. }
  95. printf("%d\n", ans);
  96. return 0;
  97. }

Luogu2483 [SDOI2010]魔法猪学院(可并堆)的更多相关文章

  1. Bzoj 1975: [Sdoi2010]魔法猪学院 dijkstra,堆,A*,K短路

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1357  Solved: 446[Submit][Statu ...

  2. BZOJ_1975_[Sdoi2010]魔法猪学院_A*

    BZOJ_1975_[Sdoi2010]魔法猪学院_A* Description iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPi ...

  3. K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...

  4. [BZOJ1975][SDOI2010]魔法猪学院(k短路,A*)

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2748  Solved: 883[Submit][Statu ...

  5. bzoj 1975: [Sdoi2010]魔法猪学院 [k短路]

    1975: [Sdoi2010]魔法猪学院 裸题... 被double坑死了 #include <iostream> #include <cstdio> #include &l ...

  6. bzoj 1975 [Sdoi2010]魔法猪学院

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1758  Solved: 557[Submit][Statu ...

  7. P2483 [SDOI2010]魔法猪学院

    P2483 [SDOI2010]魔法猪学院 摘要 --> 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世 ...

  8. 【BZOJ1975】[Sdoi2010]魔法猪学院 A*

    [BZOJ1975][Sdoi2010]魔法猪学院 Description iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪 ...

  9. bzoj1975: [Sdoi2010]魔法猪学院【k短路&A*算法】

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2446  Solved: 770[Submit][Statu ...

随机推荐

  1. day 09 课后作业

    # -*- coding: utf-8 -*-# @Time : 2018/12/28 14:25# @Author : Endless-cloud# @Site : # @File : 08 课后作 ...

  2. 类型转换:static_cast、reinterpret_cast等

    一.隐式类型转换 系统自动进行,不需要程序开发人员介入. int m = 3 + 45.6;// 48 把小数部分截掉,也属于隐式类型转换的一部分 double b = 3 + 45.6; // 48 ...

  3. javasript 的DOM 节点操作:创建,插入,删除,复制以及查找节点

    DOM 含义: DOM 是文档对象模型(Document Object Model) 是一种基于浏览器编程的一套API 接口,我W3C 出台推荐的标准.其赋予了JS 操作节点的能力,当网页被加载时,浏 ...

  4. 2016级算法期末上机-H.难题·AlvinZH's Fight with DDLs III

    1119 AlvinZH's Fight with DDLs III 思路 难题,最小点覆盖. 分析题意,某一个任务,既可以在笔记本A的 \(a\) 模式下完成,也可以在笔记本B的 \(b\) 模式下 ...

  5. eclipse如何设置UTF-8

    一.Eclipse设置utf-8编码包括两个方面,一方面可以设置workspace工作间编码,另一方面可以设置Android Project项目编码,设置步骤: 1)设置workspace工作间编码: ...

  6. [性能测试]:记录一次性能测试,nmon文件收集工具的小问题

    问题:今天发现nmon文件分析成excel后,用<NMON抽取结果.excel>无法抓取到数据 解决过程:1,认为是nmon分析文件<nmon analyser v33g.xls&g ...

  7. create-react-app安装出错问题解决

    在用create-react-app的时候 报错 错误如下图: 在SF上查到说是或许是因为国内npm拉去资源,拉去不到的问题,可以试着从解决创建create-react-app慢的方法着手: 解决方法 ...

  8. Unity3D实现随机播放背景音频

    1.先在第一人称下新建空白物体,命名“audio” 2.在audio中加入Audio Source 3.在第一人称组件里添加Audio Liistener和Audio脚本 4.脚本中添加代码 usin ...

  9. c# 操作excle[转]

    //引用Microsoft.Office.Interop.Excel.dll文件 //添加using using Microsoft.Office.Interop.Excel; using Excel ...

  10. Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. 调用函数约定不同

    Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is ...