文章目录

  • description
  • solution
  • code

【模板】k短路 / [SDOI2010]魔法猪学院

description

iPig 在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练。经过了一周理论知识和一周基本魔法的学习之后,iPig 对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的;元素与元素之间可以互相转换;能量守恒…………\ldots…………

iPig 今天就在进行一个麻烦的测验。iPig 在之前的学习中已经知道了很多种元素,并学会了可以转化这些元素的魔法,每种魔法需要消耗 iPig 一定的能量。作为 PKU 的顶尖学猪,让 iPig 用最少的能量完成从一种元素转换到另一种元素…等等,iPig 的魔法导猪可没这么笨!这一次,他给 iPig 带来了很多 1 号元素的样本,要求 iPig 使用学习过的魔法将它们一个个转化为 N 号元素,为了增加难度,要求每份样本的转换过程都不相同。这个看似困难的任务实际上对 iPig 并没有挑战性,因为,他有坚实的后盾…现在的你呀!

注意,两个元素之间的转化可能有多种魔法,转化是单向的。转化的过程中,可以转化到一个元素(包括开始元素)多次,但是一但转化到目标元素,则一份样本的转化过程结束。iPig 的总能量是有限的,所以最多能够转换的样本数一定是一个有限数。具体请参看样例。
输入格式

第一行三个数 N,M,E,表示 iPig 知道的元素个数(元素从 1 到 N 编号),iPig 已经学会的魔法个数和 iPig 的总能量。

后跟 M 行每行三个数 si,ti,ei​ 表示 iPig 知道一种魔法,消耗 ei​ 的能量将元素 si 变换到元素 ti

solution

对于原图以终点ttt为根建立一棵任意的最短路径树TTT,即我们所谓的反图

从ttt跑出到所有点的最短路disdisdis

显然,从点sss到终点ttt可能有不止一条路径,也有可能不止一条最短路

如果两条边都能出现在TTT上,且两条边又只能出现一条,那么随便选一条即可

定义:对于一条原图边u→vu\rightarrow vu→v,uuu为这条边的起点,vvv为这条边的终点

显然,如果一条原边出现在TTT上,那么vvv一定是uuu的祖先

这个最短路径树有几个性质

  • 性质Ⅰ

    对于一条s→ts\rightarrow ts→t的路径,将这条路径依次经过的边的集合,记为边集EEE,或路径EEE

    然后去掉EEE与TTT的交集,记为边集E′E'E′,或路径E′E'E′

    也就是说,一条路径PPP指代的是这条路径包含的所有边的集合

    那么对于E′E'E′中任意相邻的两条边(从原图的方向s→ts\rightarrow ts→t来看)a,ba,ba,b,即先走边aaa再走边bbb

    满足bbb的起点在TTT中为aaa的终点的祖先或者相同点

    因为a,ba,ba,b两边之间要么由树边相连,要么直接相连

  • 性质Ⅱ

    对于不在TTT的一条边eee,u,vu,vu,v分别为起点/终点,边权为www

    定义Δe=disv+w−disu\Delta_e=dis_v+w-dis_uΔe​=disv​+w−disu​,即选这条边与最短路的差值

    设LEL_ELE​为一条路径的长度,这条路径为s→ts\rightarrow ts→t

    显然有LE=∑e∈E′Δe+dissL_E=\sum_{e\in E'}\Delta_e+dis_sLE​=∑e∈E′​Δe​+diss​

  • 性质Ⅲ

    对于满足性质Ⅰ的中E′E'E′的定义的边集PPP,有且只有一条s→ts\rightarrow ts→t的路径EEE,使得P=E′P=E'P=E′

    因为TTT上任意两点之间有且仅有一条路径


这道题就转化为了求第KKK小满足性质Ⅰ的路径E′E'E′的定义的边集

最短路径肯定是TTT上的dis1dis_1dis1​

用小根堆维护边集EEE,初始为空集(事实上只要维护当前刻画出的路径的最后一条边的起点(尾端)即可,空集就是整条路径的起点sss,本题中就是点111)

一个点可以延伸多条边,也就刻画出了多条不同的路径,这些路径都需要分开记录

对于已刻画的所有路径,取出最小权值的路径EEE,设当前尾部边的起点为uuu

有两种新路径的刻画

  • 将这个边集的最后一条边,替换成另外一条以uuu为起点的权值大于等于当前边权值的非树边
  • 这条最后边的终点为vvv,在这条边的后面接一条 在TTT中为vvv祖先(含vvv自身)的点 能延伸的所有非树边的 最小边

问题就是怎么维护祖先延伸的所有非树边的最小边

从祖先转移过来,最小堆合并即可

每个点的自身信息也要保留,不能和祖先的边混合,这是为了转移Ⅰ,替换最后一条边

那么可持久化即可

:最后注意一下,以nnn为起点的边(这种魔法可以将nnn元素转化成其他元素)是不能要的
因为本题,到了nnn元素就意味着这次转化成功了,就此就终止了

你谷第一个数据点就是卡的这个小细节

code

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define Pair pair < double, int >
#define inf 0x7f7f7f7f
#define maxm 200005
#define maxn 5005
struct edge { int u, v; double w; }E[maxm];
struct node { int lson, rson, dis, End; double val; }t[maxm * 50];
priority_queue < Pair, vector < Pair >, greater < Pair > > q;
vector < int > G[maxn];
int n, m, cnt;
double En;
int f[maxn], root[maxn];
double dis[maxn];
bool vis[maxn], used[maxm];int Newnode( double val, int End ) {int now = ++ cnt;t[now].End = End;t[now].val = val;return now;
}int merge( int x, int y ) {if( ! x or ! y ) return x + y;if( t[x].val > t[y].val ) swap( x, y );int now = ++ cnt;t[now] = t[x];t[now].rson = merge( t[x].rson, y );if( t[t[now].lson].dis < t[t[now].rson].dis )swap( t[now].lson, t[now].rson );t[now].dis = t[t[now].rson].dis + 1;return now;
}void dfs( int u ) {vis[u] = 1;for( auto id : G[u] ) {auto v = E[id].v;auto w = E[id].w;if( ! vis[v] and dis[v] == dis[u] + w )f[v] = u, used[id] = 1, dfs( v );}
}int main() {scanf( "%d %d %lf", &n, &m, &En );for( int i = 1;i <= m;i ++ ) {scanf( "%d %d %lf", &E[i].v, &E[i].u, &E[i].w );if( E[i].v == n ) i --, m --;else G[E[i].u].push_back( i );}memset( dis, 0x7f, sizeof( dis ) );q.push( make_pair( dis[n] = 0, n ) );while( ! q.empty() ) {int u = q.top().second; q.pop();if( vis[u] ) continue;vis[u] = 1;for( auto id : G[u] ) {auto v = E[id].v;auto w = E[id].w;if( dis[v] > dis[u] + w )q.push( make_pair( dis[v] = dis[u] + w, v ) );}}memset( vis, 0, sizeof( vis ) );dfs( n );for( int i = 1;i <= m;i ++ )if( used[i] ) continue;else {auto u = E[i].u;auto v = E[i].v;auto w = E[i].w;if( dis[u] == inf or dis[v] == inf ) continue;else root[v] = merge( root[v], Newnode( dis[u] + w - dis[v], u ) );}for( int i = 1;i <= n;i ++ ) q.push( make_pair( dis[i], i ) );while( ! q.empty() ) {int now = q.top().second; q.pop();if( f[now] ) root[now] = merge( root[now], root[f[now]] );}int ans = 0;if( dis[1] <= En ) En -= dis[1], ans ++;if( root[1] ) q.push( make_pair( t[root[1]].val, root[1] ) );while( ! q.empty() ) {auto w = q.top().first;auto now = q.top().second;q.pop();if( dis[1] + w > En ) break;else ans ++, En -= dis[1] + w;if( t[now].lson ) //转移一 替换最后一条边q.push( make_pair( w - t[now].val + t[t[now].lson].val, t[now].lson ) );if( t[now].rson )q.push( make_pair( w - t[now].val + t[t[now].rson].val, t[now].rson ) ); if( root[t[now].End] ) //转移二 找边终点所有祖先的可扩展最小非树边 q.push( make_pair( w + t[root[t[now].End]].val, root[t[now].End] ) );}printf( "%d\n", ans );return 0;
}

【学习笔记】左偏树的可持久化(【模板】k短路 / [SDOI2010]魔法猪学院)相关推荐

  1. BZOJ1975[Sdoi2010]魔法猪学院——可持久化可并堆+最短路树

    题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的:元素与 ...

  2. 左偏树(可并堆)初步及其应用

    作者:hsez_yyh 链接:左偏树(可并堆)初步及其应用_hsez_yyh的博客-CSDN博客 来源:湖北省黄石二中信息竞赛组        著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  3. 可并堆——左偏树 Leftist Heap

    今天学习了左偏树,这是一个好理解而且好写的数据结构,和二叉堆一样可以在O(1)时间内取出优先级最高的值,O(logn)时间内删除优先级最高的值,不同的是如果要合并两个堆那么二叉堆就只能跪了.而左偏树能 ...

  4. 【学习笔记】浅谈短小可爱的左偏树(可并堆)

    文章目录 左偏树 左偏树的合并(merge)操作 例题 罗马游戏 [Apio2012]dispatching [JLOI2015]城池攻占 [Baltic2004]sequence 左偏树 左偏树是一 ...

  5. 左偏树初步学习 洛谷P3377

    玩的有点多......睡的有点少... 左偏树是一种支持O(logn)的时间复杂度内进行合并的堆式数据结构. 定义: 外结点:左儿子或者右儿子是空结点的结点 距离:一个结点x的距离disx定义为其子树 ...

  6. 【学习笔记】线段树详解(全)

    [学习笔记]线段树详解(全) 和三个同学一起搞了接近两个月的线段树,头都要炸了T_T,趁心态尚未凉之前赶快把东西记下来... [目录] [基础]作者:\((Silent\)_\(EAG)\) [懒标记 ...

  7. 【左偏树】【P3261】 [JLOI2015]城池攻占

    Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其 ...

  8. HDU 1512 Monkey King 左偏树 + 并查集

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1512 题意:有n个猴子,一开始每个猴子只认识自己.每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害. ...

  9. 《程序设计解题策略》——1.6 利用左偏树实现优先队列的合并

    本节书摘来自华章计算机<程序设计解题策略>一书中的第1章,第1.6节,作者:吴永辉 王建德 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 1.6 利用左偏树实 ...

最新文章

  1. Android Studio 打包、生成jks密钥、签名Apk、多渠道打包
  2. 请确定指定的驱动器中是否有盘_百格拉伺服驱动器维修常见故障现象及处理方法...
  3. vue部署到服务器 接口调用不了_Python 调用 Azure API 实现服务器自动部署
  4. IOS15 UICollectionViewController 如何初始化
  5. Flex DataGrid 筛选实现
  6. SQL Server 日期转换格式
  7. python数据模型_#PYTHON#数据模型 | 学步园
  8. openresty安装配置 Ubuntu下
  9. SAP BAPI_SALESORDER_CREATEFROMDAT2 创建销售订单
  10. ddm模型公式_两阶段增长模型
  11. 相关系数计算机计算方法,计算相关系数的公式(相关系数的计算方法)
  12. 软件测试工程师岗位职责、岗位要求
  13. TX-LCN分布式事务
  14. jest中的mock,jest.fn()、jest.spyOn()、jest.mock()
  15. Vokenization:一种比GPT-3更有常识的视觉语言模型
  16. 企业微信机器人脚本python_python3 企业微信机器人发送图片
  17. 计算机u盘病毒清除方式,U盘如何格式化和清理病毒
  18. 网址大放松 让网络一族网上过个新年(转)
  19. 智能共享口红机方案/案列/APP/小程序/开发
  20. 详解c语言main函数、printf函数、scanf函数与va家族

热门文章

  1. 算法有偏见?总比人类识别强吧!
  2. 小甲鱼零基础入门python二十一课课后题_小甲鱼Python第二十一讲课后习题
  3. oracle取位置,获取oracle trace文件路径
  4. php 模板替换,使用PHPWord对Word文件做模板替换
  5. 如何动态的生成某种类型的集合呢_知乎画报」的移动端动态化工程实践
  6. python插入排序_python 插入排序,选择排序
  7. idea 一直在build_让web开发部署提速 8 倍的一款 IDEA 插件,你有在用?
  8. python变量类型怎么决定的_Python数据类型提示痛点的解决方案探讨
  9. hbase shell远程连接_hbase与phoenix集成
  10. 7-1 活动选择问题 (25 分)(思路+详解+扩展)宝 今天你AC了吗!!!