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

文章目录

  • 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 vuvuuu为这条边的起点,vvv为这条边的终点

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

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

  • 性质Ⅰ

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

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

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

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

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

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

  • 性质Ⅱ

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

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

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

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

  • 性质Ⅲ

    对于满足性质Ⅰ的中E′E'E的定义的边集PPP,有且只有一条s→ts\rightarrow tst的路径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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Infinite Fraction Path UVALive - 8207

Infinite Fraction Path UVALive - 8207 题意&#xff1a; 给你n个数&#xff0c;每个数在0到9之间&#xff0c;每个数的下标一次是0~n-1&#xff0c;然后他所能走到的数为(i^21)%n,i为他本身的下标&#xff0c;然后让你求走n步&#xff0c;每一步的数相连&#xff0c;形成的…

YBTOJ洛谷P4869:出现位置(线性基)

解析 关键结论&#xff1a; 若 nnn 个数组成的线性基大小为 SSS&#xff0c;则其子集异或组成的结果有 2S2^S2S 种&#xff0c;且每种结果都有 2n−S2^{n-S}2n−S 种方案。 证明&#xff1a;考虑 n−Sn-Sn−S 个没有加入线性基的元素的任意一个子集&#xff0c;其异或和为 xxx…

.NET Core开源行动:一键创建Excel Add-in

作为.NET Core开源行动的一部分&#xff0c;我此前已经创建和发布了一套基于.NET Core的Office 365开发模板库&#xff0c;是针对Microsoft Graph开发的场景的&#xff0c;有兴趣可以参考 https://github.com/chenxizhang/dotnetcore-office365dev-templates-msgraph &#xff…

【学习笔记】最小生成树系列的必做经典题

最小生成树系列【模板】最小生成树prim算法kruskal算法Borůvka (Sollin)算法次小生成树最小生成树计数最优比率生成树最小乘积生成树最小度限制生成树最小方差树【模板】最小生成树 prim算法 最小生成树的prim\text{prim}prim类似于最短路的dijkstra\text{dijkstra}dijkstra…

2017 ICPC沈阳区域赛

2017 沈阳区域赛 题号题目难度知识点ABBP FormulaBBridgeCEmpty Convex PolygonsDDefense of the AncientsEFive-round Show HandFHeron and His Triangle铜牌题推式子思维GInfinite Fraction Path快银稳铜dfs剪枝HLegends of the Three KingdomsILittle Boxes签到题大数JNew …

YBROJ洛谷P3211:XOR和路径(线性基,期望dp)

解析 不难想到第一步利用期望线性性逐位考虑。 然后就变成求一个布尔变量的期望了&#xff0c;可以直接转化为求概率。 我一开始的想求从1出发异或和为0/1的概率&#xff0c;然而这个东西在原点1附近的转移特别别扭…老出现概率大于1的迷惑情况。 然后我就不会了 正解是反过…

切题 (problem)(线段树+最大流最小割)

切题 problemdescriptionsolutioncodedescription 在一个神秘的 JOSLFN 上&#xff0c;wzy 和 lqs2015 常年占据着切题榜的 rk1 和 rk2。现在他们在研究 如何快速造题并验题。 分工是这样的&#xff1a;有 n 个 wzy 负责造题&#xff0c;第 i 个 wzy 会造出恰好 ai 道题。有 m…

通过 Azure Pipelines 实现持续集成之docker容器化

IntroAzure DevOps Pipeline 现在对于公开的项目完全免费&#xff0c;这对于开源项目来讲无疑是个巨大的好消息&#xff0c;在 Github 的 Marketplace 里有个 Azure Pipeline&#xff0c;就是微软的 Azure DevOps Pipeline。实现 Docker 容器化的持续集成实现的目标&#xff1a…

YBTOJ:最小数(欧拉函数)

解析 题意可以化为&#xff1a; 8∗10x−19kn08*\frac{10^x-1}{9}kn08∗910x−1​kn0 然后用 8 尽可能的消去 9n9n9n 中的2的幂次&#xff0c;随后问题转化为&#xff1a; 10x≡1(modn′)10^x\equiv 1\pmod {n}10x≡1(modn′) 然后…我就觉得这个是exbsgs了… 但其实完全不用阿…

Acwing 1082. 数字游戏

Acwing 1082. 数字游戏 题意&#xff1a; 现在大家决定玩一个游戏&#xff0c;指定一个整数闭区间 [a,b]&#xff0c;问这个区间内有多少个不降数。 题解&#xff1a; 利用数位dp的套路来做 我们还是利用前缀和来做 我们先求1~n中满足情况的个数 对于一个n位数&#xff0c;…

天下第一 txdy (LCT+双指针+线段树)

天下第一 txdydescriptionsolutioncodedescription djq_cpp 是天下第一的。 djq_cpp 给了你一个 n 个点 m 条边的无向图&#xff08;无重边自环&#xff09;&#xff0c;点标号为 1 ∼n。祂想要考考你&#xff0c; 有多少对整数对 (l, r) 满足&#xff1a; • 1 ≤l ≤r ≤n •…

Acwing 1083. Windy数

Acwing 1083. Windy数 题意&#xff1a; Windy 定义了一种 Windy 数&#xff1a;不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。 Windy 想知道&#xff0c;在 A 和 B 之间&#xff0c;包括 A 和 B&#xff0c;总共有多少个 Windy 数&#xff1f; 题解&am…

【招聘(南京)】南京纳龙科技有限公司招高级.net开发工程师

南京纳龙科技有限公司成立于2002年12月&#xff0c;隶属纳龙科技在南京成立的研发中心&#xff0c;坐落于南京市雨花台区。公司立志以守护人类心脏健康为使命&#xff0c;专注推动心电信息化技术的发展&#xff0c;为全国各级医疗机构提供心电检查、诊断一体化的解决方案。公司…

模板:k短路(可并堆)

所谓k短路&#xff0c;就是第k短的路。 &#xff08;逃&#xff09; 解析 给出一个有向图&#xff0c;求 s−ts-ts−t 的不严格第 k 短的路径。 A*算法 对于一个状态 (x,cost)(x,cost)(x,cost)&#xff0c;即到 xxx 时走过长度为 costcostcost&#xff0c;定义一个估价函数&a…

大鱼吃小鱼(fhq-treap/线段树二分+贪心)

大鱼吃小鱼descriptionsolutioncodedescription 《大鱼吃小鱼》是一款经典的儿童益智类游戏&#xff0c;在游戏中&#xff0c;玩家所操控的“大鱼”只能吃掉体积严格小于自己的“小鱼”&#xff0c;然后玩家所操控的“大鱼”的体积就会增加“小鱼”的体积这么多的量。 知名主…

Acwing 1081. 度的数量(以及本人对数位dp的浅薄理解)

题意&#xff1a; 求给定区间 [X,Y] 中满足下列条件的整数个数&#xff1a;这个数恰好等于 K 个互不相等的 B 的整数次幂之和。 题解&#xff1a; 数位DP 技巧1&#xff1a;[X,Y]>f(Y)-f(X-1) 技巧2&#xff1a;用树的方式来考虑。 在本题中&#xff0c;题意是问[X,Y]中…

EFCore动态切换Schema

最近做个分库分表项目&#xff0c;用到schema的切换感觉还是有些坑的&#xff0c;在此分享下。 先简要说下我们的分库分表分库分表规则我定的规则是&#xff0c;订单号&#xff08;数字&#xff09;除以16&#xff0c;得出的结果为这个订单所在的数据库&#xff0c;然后他的余数…

YBTOJ:工作评估(分块)

解析 首先想想 O(nm)O(nm)O(nm) 怎么做。 从左往右扫&#xff0c;不断把当前值和 x0x_0x0​ 取 max⁡\maxmax 即可。 考虑正解&#xff1a; 设 f(l,r,w)f(l,r,w)f(l,r,w) 为初始为 www&#xff0c;工作区间为 (l,r)(l,r)(l,r) 结束后的价值&#xff0c;s(l,r)∑ilrais(l,r)\s…

黑客(续) (压位高精+状压dp)

黑客&#xff08;续&#xff09;descriptionsolutioncodedescription 【问题描述】 在破解了世界首富 Bychaha 的银行账户后&#xff0c;知名黑客 pks 发现&#xff0c;要得到 Bychaha 的全部财产&#xff0c;必须再破解一道密码。 作为客户账户安全的最后一道防线&#xff0…

东莞.NET俱乐部线下技术沙龙-活动报名

自广州.NET技术俱乐部在2018年12月08日线下活动顺利开展后&#xff0c;东莞作为兄弟城市&#xff0c;也想通过线下活动的方式&#xff0c;点燃东莞.NET技术的熊熊之火。现决定先借助广州、深圳兄弟城市的帮助下&#xff0c;开展一场东莞方主办的线下活动&#xff0c;聚集东莞本…