luogu 2483 K短路 (可持久化左偏树)
题面:
题目大意:给你一张有向图,求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短路 (可持久化左偏树)的更多相关文章
- Luogu P4331 [BOI2004]Sequence 数字序列 (左偏树论文题)
清晰明了%%% Fairycastle的博客 个人习惯把size什么的存在左偏树结点内,这样在外面好写,在里面就是模板(只用修改update). 可以对比一下代码(好像也差不多-) MY CODE # ...
- k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)
你谷数据够强了,以前的A*应该差不多死掉了. 所以,小伙伴们快来一起把YL顶上去把!戳这里! 俞鼎力的课件 需要掌握的内容: Dijkstra构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...
- luogu【P3377】 【模板】左偏树
左偏树 顾名思义 向左偏的树 (原题入口) 它有啥子用呢??? 当然是进行堆的合并啦2333普通堆的合并其实是有点慢的(用优先队列的话 只能 一个pop 一个push 来操作 复杂度就是O(n log ...
- Luogu P1552 [APIO2012]派遣【左偏树】By cellur925
题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...
- YbtOJ#631-次短路径【左偏树,最短路】
正题 题目链接:https://www.ybtoj.com.cn/contest/114/problem/1 题目大意 给出\(n\)个点\(m\)条边的一张无向图,对于每个点\(i\)求不经过\(i ...
- BZOJ 4003 / Luogu P3261 [JLOI2015]城池攻占 (左偏树)
左偏树裸题,在树上合并儿子传上来的堆,然后小于当前结点防御值的就pop掉,pop的时候统计答案. 修改的话就像平衡树一样打懒标记就行了. 具体见代码 CODE #include<bits/std ...
- 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集
https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...
- BZOJ 1455 罗马游戏 ——左偏树
[题目分析] 左偏树的模板题目,大概就是尽量维护树的深度保持平衡,以及尽可能的快速合并的一种堆. 感觉和启发式合并基本相同. 其实并没有快很多. 本人的左偏树代码自带大常数,借鉴请慎重 [代码] #i ...
- 【BZOJ-1455】罗马游戏 可并堆 (左偏树)
1455: 罗马游戏 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1355 Solved: 561[Submit][Status][Discuss] ...
随机推荐
- springmvc 时间返回格式化
如果是@ResponseBody,可以通过@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")设置返回的样式: 如果是不是@ResponseBody ...
- leetcode第一刷_Minimum Window Substring
好题.字符串.线性时间. 我认为第一次拿到这个题的人应该不会知道该怎么做吧,要么就是我太弱了..先搞清楚这个题要求的是什么.从一个长字符串中找一个字串,这个字串中的字符全然包括了另一个给定目标串中的字 ...
- SQL Server高速导入数据分享
SQL Server高速导入数据,能够尝试的方法例如以下:CTE.OpenRowSet/OpenDataSource.BULK INSERT.bcp.Shell. 以下依次介绍这几种办法. 1.CTE ...
- wpf 样式的调用
这个针对异地调用: 1.在主程序的项目中新建一个Skins的目录.然后再目录里新建一个BlackSkin.xaml的字典资源: <ResourceDictionary xmlns="h ...
- 初触Python,关于pyquery解析html(百度贴吧)
一直听同事说Python是个奇妙的语言,上周在逛知乎的时候深受这个话题的启示. 能利用爬虫技术做到哪些非常酷非常有趣非常实用的事情? 先是说到IDE的选择,作为python新人,尽管知道mac终端自带 ...
- hdu 4932 Miaomiao's Geometry(暴力枚举)
pid=4932">Miaomiao's Geometry ...
- mysql 日期计算,今天,明天,本周,下周,本月,下月
--今天 DATE_FORMAT(BIRTH_DATE,'%Y-%m-%d') = CURDATE() --明天 DATE_FORMAT(BIRTH_DATE,'%Y-%m-%d') = TIMEST ...
- ASP.NET MVC脚本及样式压缩
现在我用ASP.NET MVC4.0,发现它自带有脚本和样式压缩功能.不知道以前的版本有木有,没有深究.太棒了!以前我们还辛辛苦苦自己搞了一个压缩的东西.这再次说明,平庸程序员如我辈,应该把时间和精力 ...
- rpmbuild
rpm2cpio xxx.rpm | cpio -div
- 应用JavaScript搭建一个简易页面图片无缝滚动效果
页面图片无缝滚动JavaScript原理:移动的区块包含图片内容,区块相对父级元素进行定位脱离文档流.再令区块的left值每隔固定的时间进行等量减少(或增大)从而实现区块的匀速运动.由于每次间隔移动的 ...