题面:

题目大意:给你一张有向图,求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. Equals和==的差别

    java中的数据类型.可分为两类:  1.基本数据类型 包含:byte,short,char,int,long,float,double,boolean .基础数据类型比較大小的时候使用的是双等号(= ...

  2. [Cypress] Create Aliases for DOM Elements in Cypress Tests

    We’ll often need to access the same DOM elements multiple times in one test. Your first instinct mig ...

  3. SharePoint 2013 关闭 customErrors

    在SharePoint 2013上做开发时,如果不把customErrors 关掉,那调试起来那真叫一个费劲.在2013里,关闭customErrors 和2010一样,只要把文件路径改成15目录下即 ...

  4. 一步步玩pcDuino3--mmc下的bootloader

    pcDuino3下支持mmc启动.官方的Uboot是採用SPL框架实现的,由于内部的SRAM空间达到32K,我们全然能够在这32K空间内编写一个完整可用小巧的bootloader来完毕引导Linux ...

  5. 如何让 vue 在 sublime 中变成彩色的

    在 sublime 中编辑 vue 时,导入后是纯白色的文本,如下图: 想让其变成彩色的文本,需要安装插件,步骤如下: 1. 按住:Ctrl + Alt + P 2. 输入:install Packa ...

  6. 【POJ2248、LOJ#10021】 Addition Chains

    事先预警:由于我太蒻了,本做法只能在POJ.LOJ等小数据(N<=100)平台上通过,在UVa(洛谷)上大数据并不能通过 戳我获得更好的观看效果 本题不用看,爆搜就是了,但是纯爆搜显然会爆时间, ...

  7. Spring Boot (1) 构建第一个Spring Boot工程

    Spring boot简介 spring boot是spring官方推出的一个全新框架,其设计目的是用来简化新spring应用的初始搭建以及开发过程. Spring boot特点 1.化繁为简,简化配 ...

  8. angular js 公告墙

    <!DOCTYPE html>   <html lang="en">   <head>   <meta charset="UTF ...

  9. python爬虫:找房助手V1.0-爬取58同城租房信息

    1.用于爬取58上的租房信息,限成都,其他地方的,可以把网址改改: 2.这个爬虫有一点问题,就是没用多线程,因为我用了之后总是会报: 'module' object has no attribute ...

  10. DB2数据常用指令

    ************************************************************** 这个只是个人平时总结,如果有更好的欢迎告诉我,一起学习一起成长 ***** ...