题面:

题目大意:给你一张有向图,求1到n的第k短路

$K$短路模板题

假设整个图的边集为$G$

首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$

那么每个点沿着树边走到点$n$,它对于答案的贡献为0

我们加入一条非树边,它对于答案的贡献就是$delta(u,v)=dis[v]+e(u,v)-dis[u]$,即如果选择了这条边,这条路径的长度就会增加$delta(u,v)$

那么一条路径$p$的总长度就是$dis_{min}+\sum\limits_{e\in p,e\in G-T} delta(e)$

我们现在要求出前$K$条总长度最小的路径长度,(即使在这道题里我们不知道K是多少)

我们首先向一个堆中加入一条非树边,然后依次拓展,拓展的过程是这样的:

每次从堆中取出一条边集$p$,然后有两种情况

1.把末尾这条边替换成,这条边原来所在的边集里,边权大于等于它的一条边

2.新加入一条,末尾这条边的终点$v$,在最短路树里的一个祖先所能扩展的一条最短的非树边

这样扩展保证了每次新产生的边集贡献$\geq $原来的边集贡献,保证了有序性

且每次都选择最短的边集,保证了同一种边集不会重复讨论

第二个操作需要找出最小的后继状态,而后继状态可能很多,想办法用数据结构维护

在最短路树上每个点都维护反向非树边的集合,那么子节点也要包含父节点的集合,需要可持久化

而对于第一个操作,我们需要一个有序表来扩展,所以要用到堆之类的东西

可持久化可并堆!

无非就是$merge$里每次合并都新建节点罢了

第一个操作就是把最后一条边换成这条边在堆中的左右儿子

第二个操作直接取堆顶即可

这也是类似于普通$dijkstra$最短路的扩展过程

  1. #include <queue>
  2. #include <cmath>
  3. #include <vector>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <algorithm>
  7. #define N1 5010
  8. #define M1 200010
  9. #define S1 N1<<8
  10. #define ll long long
  11. #define dd double
  12. using namespace std;
  13. const dd eps=1e-;
  14.  
  15. template <typename _T> void read(_T &ret)
  16. {
  17. ret=; _T fh=; char c=getchar();
  18. while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
  19. while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
  20. ret=ret*fh;
  21. }
  22.  
  23. int n,m;
  24. struct Edge{
  25. int to[M1<<],nxt[M1<<],val[M1<<],head[N1],cte; dd dis[M1<<];
  26. void ae(int u,int v,dd d)
  27. {
  28. cte++; to[cte]=v; nxt[cte]=head[u];
  29. head[u]=cte; dis[cte]=d;
  30. }
  31. }e;
  32.  
  33. struct node1{
  34. int x; dd d;
  35. node1(int x,dd d):x(x),d(d){} node1(){}
  36. friend bool operator < (const node1 &s1,const node1 &s2)
  37. {
  38. return s1.d>s2.d;
  39. }
  40. };
  41.  
  42. struct Heap{
  43. int ch[S1][],h[S1],root0[N1],root1[N1],tot; node1 val[S1];
  44. int merge0(int x,int y)
  45. {
  46. if(!x||!y) return x+y;
  47. if(val[x]<val[y]) swap(x,y);
  48. ch[x][]=merge0(ch[x][],y);
  49. if(h[ch[x][]]<h[ch[x][]]) swap(ch[x][],ch[x][]);
  50. h[x]=h[ch[x][]]+;
  51. return x;
  52. }
  53. int merge1(int x,int y)
  54. {
  55. if(!x||!y) return x+y;
  56. if(val[x]<val[y]) swap(x,y);
  57. int nx=++tot; val[nx]=val[x]; ch[nx][]=ch[x][]; ch[nx][]=ch[x][]; h[nx]=h[x];
  58. ch[nx][]=merge1(ch[x][],y);
  59. if(h[ch[nx][]]<h[ch[nx][]]) swap(ch[nx][],ch[nx][]);
  60. h[nx]=h[ch[nx][]]+;
  61. return nx;
  62. }
  63. }h;
  64.  
  65. priority_queue<node1>q;
  66. int use[N1]; dd dis[N1];
  67. void dijkstra()
  68. {
  69. node1 k; int x,j,v;
  70. q.push(node1(n,)); dis[n]=;
  71. for(j=;j<n;j++) dis[j]=;
  72. while(!q.empty())
  73. {
  74. k=q.top(); q.pop(); x=k.x;
  75. if(use[x]) continue; use[x]=;
  76. for(j=e.head[x];j;j=e.nxt[j])
  77. {
  78. v=e.to[j];
  79. if(dis[v]-eps>dis[x]+e.dis[j])
  80. {
  81. dis[v]=dis[x]+e.dis[j];
  82. q.push(node1(v,dis[v]));
  83. }
  84. }
  85. }
  86. }
  87. int fa[N1],de; dd la[N1];
  88. void dfs_tree(int x)
  89. {
  90. int j,v;
  91. if(fa[x]) h.root1[x]=h.merge1(h.root1[fa[x]],h.root0[x]);
  92. for(j=e.head[x];j;j=e.nxt[j])
  93. {
  94. v=e.to[j]; if(!e.val[j]) continue;
  95. dfs_tree(v);
  96. }
  97. }
  98. void build_tree()
  99. {
  100. int i,x,j,v;
  101. for(i=;i<=n;i++)
  102. {
  103. for(j=e.head[i];j;j=e.nxt[j])
  104. {
  105. v=e.to[j];
  106. if(!fa[v]&&fabs(dis[i]+e.dis[j]-dis[v])<eps)
  107. e.val[j]^=, fa[v]=i;
  108. }
  109. }
  110. for(x=;x<=n;x++)
  111. {
  112. for(j=e.head[x];j;j=e.nxt[j])
  113. {
  114. v=e.to[j]; if(e.val[j]) continue;
  115. h.val[++h.tot]=node1(x,dis[x]+e.dis[j]-dis[v]);
  116. h.root0[v]=h.merge0(h.root0[v],h.tot);
  117. }
  118. }
  119. }
  120. dd E;
  121. struct node2{
  122. int x,v; dd d,D;
  123. node2(int x,int v,dd d,dd D):x(x),v(v),d(d),D(D){} node2(){}
  124. friend bool operator < (const node2 &s1,const node2 &s2)
  125. {
  126. return s1.D>s2.D;
  127. }
  128. };
  129. priority_queue<node2>que;
  130.  
  131. void debug()
  132. {
  133. int x=;
  134. while(fa[x]) printf("%d ",fa[x]), x=fa[x];
  135. puts("");
  136. }
  137.  
  138. int main()
  139. {
  140. //freopen("testdata.in","r",stdin);
  141. scanf("%d%d%lf",&n,&m,&E);
  142. int i,j,k,x,y,v,xx,vv,ans=; dd d,now,w;
  143. for(i=;i<=m;i++)
  144. {
  145. read(x), read(y), scanf("%lf",&d);
  146. e.ae(y,x,d);
  147. }
  148. dijkstra();
  149. build_tree();
  150. dfs_tree(n);
  151. node2 K;
  152. que.push(node2(,,,)); ans=;
  153. //debug();
  154. while(!que.empty())
  155. {
  156. K=que.top(); que.pop(); x=K.x; v=K.v; E-=K.D+dis[];
  157. //printf("%lf\n",K.D+dis[1]);
  158. if(E>-eps) ans++; else break;
  159. if(h.root1[v])
  160. {
  161. j=h.root1[v]; vv=h.val[j].x; w=h.val[j].d;
  162. que.push(node2(j,vv,w,K.D+w));
  163. }
  164. if(h.ch[x][])
  165. {
  166. j=h.ch[x][]; vv=h.val[j].x; w=h.val[j].d;
  167. que.push(node2(j,vv,w,K.D-K.d+w));
  168. }
  169. if(h.ch[x][])
  170. {
  171. j=h.ch[x][]; vv=h.val[j].x; w=h.val[j].d;
  172. que.push(node2(j,vv,w,K.D-K.d+w));
  173. }
  174. }
  175. printf("%d\n",ans);
  176. return ;
  177. }

luogu 2483 K短路 (可持久化左偏树)的更多相关文章

  1. Luogu P4331 [BOI2004]Sequence 数字序列 (左偏树论文题)

    清晰明了%%% Fairycastle的博客 个人习惯把size什么的存在左偏树结点内,这样在外面好写,在里面就是模板(只用修改update). 可以对比一下代码(好像也差不多-) MY CODE # ...

  2. k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)

    你谷数据够强了,以前的A*应该差不多死掉了. 所以,小伙伴们快来一起把YL顶上去把!戳这里! 俞鼎力的课件 需要掌握的内容: Dijkstra构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...

  3. luogu【P3377】 【模板】左偏树

    左偏树 顾名思义 向左偏的树 (原题入口) 它有啥子用呢??? 当然是进行堆的合并啦2333普通堆的合并其实是有点慢的(用优先队列的话 只能 一个pop 一个push 来操作 复杂度就是O(n log ...

  4. Luogu P1552 [APIO2012]派遣【左偏树】By cellur925

    题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...

  5. YbtOJ#631-次短路径【左偏树,最短路】

    正题 题目链接:https://www.ybtoj.com.cn/contest/114/problem/1 题目大意 给出\(n\)个点\(m\)条边的一张无向图,对于每个点\(i\)求不经过\(i ...

  6. BZOJ 4003 / Luogu P3261 [JLOI2015]城池攻占 (左偏树)

    左偏树裸题,在树上合并儿子传上来的堆,然后小于当前结点防御值的就pop掉,pop的时候统计答案. 修改的话就像平衡树一样打懒标记就行了. 具体见代码 CODE #include<bits/std ...

  7. 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集

    https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...

  8. BZOJ 1455 罗马游戏 ——左偏树

    [题目分析] 左偏树的模板题目,大概就是尽量维护树的深度保持平衡,以及尽可能的快速合并的一种堆. 感觉和启发式合并基本相同. 其实并没有快很多. 本人的左偏树代码自带大常数,借鉴请慎重 [代码] #i ...

  9. 【BZOJ-1455】罗马游戏 可并堆 (左偏树)

    1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1355  Solved: 561[Submit][Status][Discuss] ...

随机推荐

  1. springmvc 时间返回格式化

    如果是@ResponseBody,可以通过@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")设置返回的样式: 如果是不是@ResponseBody ...

  2. leetcode第一刷_Minimum Window Substring

    好题.字符串.线性时间. 我认为第一次拿到这个题的人应该不会知道该怎么做吧,要么就是我太弱了..先搞清楚这个题要求的是什么.从一个长字符串中找一个字串,这个字串中的字符全然包括了另一个给定目标串中的字 ...

  3. SQL Server高速导入数据分享

    SQL Server高速导入数据,能够尝试的方法例如以下:CTE.OpenRowSet/OpenDataSource.BULK INSERT.bcp.Shell. 以下依次介绍这几种办法. 1.CTE ...

  4. wpf 样式的调用

    这个针对异地调用: 1.在主程序的项目中新建一个Skins的目录.然后再目录里新建一个BlackSkin.xaml的字典资源: <ResourceDictionary xmlns="h ...

  5. 初触Python,关于pyquery解析html(百度贴吧)

    一直听同事说Python是个奇妙的语言,上周在逛知乎的时候深受这个话题的启示. 能利用爬虫技术做到哪些非常酷非常有趣非常实用的事情? 先是说到IDE的选择,作为python新人,尽管知道mac终端自带 ...

  6. hdu 4932 Miaomiao&#39;s Geometry(暴力枚举)

    pid=4932">Miaomiao's Geometry                                                               ...

  7. mysql 日期计算,今天,明天,本周,下周,本月,下月

    --今天 DATE_FORMAT(BIRTH_DATE,'%Y-%m-%d') = CURDATE() --明天 DATE_FORMAT(BIRTH_DATE,'%Y-%m-%d') = TIMEST ...

  8. ASP.NET MVC脚本及样式压缩

    现在我用ASP.NET MVC4.0,发现它自带有脚本和样式压缩功能.不知道以前的版本有木有,没有深究.太棒了!以前我们还辛辛苦苦自己搞了一个压缩的东西.这再次说明,平庸程序员如我辈,应该把时间和精力 ...

  9. rpmbuild

    rpm2cpio xxx.rpm | cpio -div

  10. 应用JavaScript搭建一个简易页面图片无缝滚动效果

    页面图片无缝滚动JavaScript原理:移动的区块包含图片内容,区块相对父级元素进行定位脱离文档流.再令区块的left值每隔固定的时间进行等量减少(或增大)从而实现区块的匀速运动.由于每次间隔移动的 ...