题面:

题目大意:给你一张有向图,求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$最短路的扩展过程

 #include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 5010
#define M1 200010
#define S1 N1<<8
#define ll long long
#define dd double
using namespace std;
const dd eps=1e-; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
} int n,m;
struct Edge{
int to[M1<<],nxt[M1<<],val[M1<<],head[N1],cte; dd dis[M1<<];
void ae(int u,int v,dd d)
{
cte++; to[cte]=v; nxt[cte]=head[u];
head[u]=cte; dis[cte]=d;
}
}e; struct node1{
int x; dd d;
node1(int x,dd d):x(x),d(d){} node1(){}
friend bool operator < (const node1 &s1,const node1 &s2)
{
return s1.d>s2.d;
}
}; struct Heap{
int ch[S1][],h[S1],root0[N1],root1[N1],tot; node1 val[S1];
int merge0(int x,int y)
{
if(!x||!y) return x+y;
if(val[x]<val[y]) swap(x,y);
ch[x][]=merge0(ch[x][],y);
if(h[ch[x][]]<h[ch[x][]]) swap(ch[x][],ch[x][]);
h[x]=h[ch[x][]]+;
return x;
}
int merge1(int x,int y)
{
if(!x||!y) return x+y;
if(val[x]<val[y]) swap(x,y);
int nx=++tot; val[nx]=val[x]; ch[nx][]=ch[x][]; ch[nx][]=ch[x][]; h[nx]=h[x];
ch[nx][]=merge1(ch[x][],y);
if(h[ch[nx][]]<h[ch[nx][]]) swap(ch[nx][],ch[nx][]);
h[nx]=h[ch[nx][]]+;
return nx;
}
}h; priority_queue<node1>q;
int use[N1]; dd dis[N1];
void dijkstra()
{
node1 k; int x,j,v;
q.push(node1(n,)); dis[n]=;
for(j=;j<n;j++) dis[j]=;
while(!q.empty())
{
k=q.top(); q.pop(); x=k.x;
if(use[x]) continue; use[x]=;
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j];
if(dis[v]-eps>dis[x]+e.dis[j])
{
dis[v]=dis[x]+e.dis[j];
q.push(node1(v,dis[v]));
}
}
}
}
int fa[N1],de; dd la[N1];
void dfs_tree(int x)
{
int j,v;
if(fa[x]) h.root1[x]=h.merge1(h.root1[fa[x]],h.root0[x]);
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j]; if(!e.val[j]) continue;
dfs_tree(v);
}
}
void build_tree()
{
int i,x,j,v;
for(i=;i<=n;i++)
{
for(j=e.head[i];j;j=e.nxt[j])
{
v=e.to[j];
if(!fa[v]&&fabs(dis[i]+e.dis[j]-dis[v])<eps)
e.val[j]^=, fa[v]=i;
}
}
for(x=;x<=n;x++)
{
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j]; if(e.val[j]) continue;
h.val[++h.tot]=node1(x,dis[x]+e.dis[j]-dis[v]);
h.root0[v]=h.merge0(h.root0[v],h.tot);
}
}
}
dd E;
struct node2{
int x,v; dd d,D;
node2(int x,int v,dd d,dd D):x(x),v(v),d(d),D(D){} node2(){}
friend bool operator < (const node2 &s1,const node2 &s2)
{
return s1.D>s2.D;
}
};
priority_queue<node2>que; void debug()
{
int x=;
while(fa[x]) printf("%d ",fa[x]), x=fa[x];
puts("");
} int main()
{
//freopen("testdata.in","r",stdin);
scanf("%d%d%lf",&n,&m,&E);
int i,j,k,x,y,v,xx,vv,ans=; dd d,now,w;
for(i=;i<=m;i++)
{
read(x), read(y), scanf("%lf",&d);
e.ae(y,x,d);
}
dijkstra();
build_tree();
dfs_tree(n);
node2 K;
que.push(node2(,,,)); ans=;
//debug();
while(!que.empty())
{
K=que.top(); que.pop(); x=K.x; v=K.v; E-=K.D+dis[];
//printf("%lf\n",K.D+dis[1]);
if(E>-eps) ans++; else break;
if(h.root1[v])
{
j=h.root1[v]; vv=h.val[j].x; w=h.val[j].d;
que.push(node2(j,vv,w,K.D+w));
}
if(h.ch[x][])
{
j=h.ch[x][]; vv=h.val[j].x; w=h.val[j].d;
que.push(node2(j,vv,w,K.D-K.d+w));
}
if(h.ch[x][])
{
j=h.ch[x][]; vv=h.val[j].x; w=h.val[j].d;
que.push(node2(j,vv,w,K.D-K.d+w));
}
}
printf("%d\n",ans);
return ;
}

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. HDU 5392 Infoplane in Tina Town

    Infoplane in Tina Town Time Limit: 14000/7000 MS (Java/Others)    Memory Limit: 524288/524288 K (Jav ...

  2. 使用golang来设计我们的Ubuntu Scope

    我们知道golang越来越被非常多的开发人员来开发应用.go语言也能够用于开发Ubuntu Scope. 在今天的教程中.我们将具体介绍怎样使用go语言来开发我们的Scope.这对于非常多的不太熟悉C ...

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

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

  4. luogu2152 [SDOI2009]SuperGCD

    要你求两个非常大的数字的GCD. 不要想复杂,用高精度整更相减损术即可. #include <cstdio> #include <cstring> #include <a ...

  5. poj 2288 Islands and Bridges ——状压DP

    题目:http://poj.org/problem?id=2288 状压挺明显的: 一开始写了(记忆化)搜索,但一直T: #include<iostream> #include<cs ...

  6. 第2章 安装Nodejs 2-3 Windows下安装Nodejs

    http://nodejs.org

  7. Android开发中的日期格式化

    下面的转换符来自Java,但是在android中同样可用.(以下表格内容来自互联网.) 常见日期格式化转换符 转换符 说 明 示 例 %te  一个月中的某一天(1-31)  2 %tb  指定语言环 ...

  8. B - String Task

    Problem description Petya started to attend programming lessons. On the first lesson his task was to ...

  9. Spring boot (12) tomcat jdbc连接池

    默认连接池 tomcat jdbc是从tomcat7开始推出的一个连接池,相比老的dbcp连接池要优秀很多,spring boot将tomcat jdbc作为默认的连接池,只要在pom.xml中引入了 ...

  10. Visual C++ 6.0的界面介绍

      双击Visual C++ 6.0安装目录下的文件启动Visual C++ 6.0,通过“文件”→“新建”可新建一个Win32 Console Application项目.创建好项目后,显示Visu ...