这种东西到现在才学……

考虑 \(T\) 为根的最短路树,一条路径一定是树上边和非树边交错。

我们只管非树边,对于一条路径,非树边构成一个序列 \(L\),相邻两条路径 \(\left(u_1,v_1\right)\) ,\(\left(u_2,v_2\right)\) 显然一定满足 \(u_2\) 是 \(v_1\) 的祖先。

有了这个性质,我们可以解决这个问题。

考虑最后一条边的转移。要么是转移到答案,即 \(dis_u + val + dis_v\),要么再选择一条边转移,即 \(dis_u' = dis_u + val + dis_{u,v}\),其中 \(v\) 是下一条边的 \(u\) 的最近祖先端点。

显然可以用堆维护。由于答案是两个转移式结合,显然还是太繁了。不如直接把所有边权改为 \(val' = val + dis_v - dis_u\),那么显然经过一条边只是最短路的增量。

每次一条边的转移直接把距离加上 \(val'\) 即可。

调试的时候把最短路数组和左偏树数组混用了 /px

#include <bits/stdc++.h>

const int MAXN = 5010;
const int MAXE = 200010;
const int MAXP = 2000000;
const double eps = 1e-6;
int n, m;
int xs[MAXE], ys[MAXE];
double vs[MAXE], E, dis[MAXN];
std::vector<int> G[MAXN], el[MAXN];
inline bool eq(double x) { return -eps < x && x < eps; }
struct node {
int to, ls, rs; double val;
} tree[MAXP];
int tot;
int dx[MAXP];
int merge(int x, int y) {
if (!x || !y) return x | y;
if (tree[x].val > tree[y].val) std::swap(x, y);
int now = ++tot; node & t= tree[now] = tree[x];
t.rs = merge(t.rs, y);
if (dx[t.ls] < dx[t.rs]) std::swap(t.ls, t.rs);
dx[now] = dx[t.rs] + 1;
return now;
}
void shortestpath() {
for (int i = 1; i <= m; ++i)
G[ys[i]].push_back(i);
for (int i = 0; i < n; ++i)
dis[i] = 1e20;
dis[n] = 0;
static bool vis[MAXN];
for (int i = 1; i <= n; ++i) {
int at = 0;
for (int j = 1; j <= n; ++j)
if (!vis[j] && dis[j] < dis[at])
at = j;
vis[at] = true;
const int SZ = G[at].size();
for (int j = 0; j != SZ; ++j) {
int u = G[at][j];
dis[xs[u]] = std::min(dis[xs[u]], dis[at] + vs[u]);
}
}
memset(vis, 0, n + 1);
for (int i = 1; i <= n; ++i) G[i].clear();
for (int i = 1; i <= m; ++i)
if (eq(-dis[xs[i]] + dis[ys[i]] + vs[i]))
if (!vis[xs[i]]) {
vis[xs[i]] = true;
G[ys[i]].push_back(xs[i]);
}
for (int i = 1; i <= m; ++i)
el[xs[i]].push_back(i);
}
int rt[MAXN];
void dfs(int u, int fa = 0) {
rt[u] = rt[fa];
const int LZ = el[u].size();
bool fir = false;
for (int i = 0; i != LZ; ++i) {
int at = el[u][i];
double v = dis[ys[at]] + vs[at] - dis[u];
if (v < eps && !fir) { fir = true; continue; }
++tot;
tree[tot].to = ys[at];
tree[tot].val = v;
rt[u] = merge(rt[u], tot);
}
const int SZ = G[u].size();
for (int i = 0; i != SZ; ++i)
dfs(G[u][i], u);
}
struct qs {
int rt; double v;
bool operator < (const qs & b) const {
return v > b.v;
}
} ;
std::priority_queue<qs> q;
qs trans(int rt, double v) {
qs res;
res.rt = rt, res.v = v + tree[rt].val;
return res;
}
int main() {
std::ios_base::sync_with_stdio(false), std::cin.tie(0);
std::cin >> n >> m >> E;
for (int i = 1; i <= m; ++i)
std::cin >> xs[i] >> ys[i] >> vs[i];
shortestpath();
dfs(n);
++tot; tree[tot].to = 1;
tree[tot].val = dis[1];
q.push(trans(tot, 0));
int ans = 0;
while (true) {
qs x = q.top(); q.pop();
E -= x.v;
if (E + eps <= 0) break;
++ans;
if (int t = rt[tree[x.rt].to])
q.push(trans(t, x.v));
x.v -= tree[x.rt].val;
x.rt = merge(tree[x.rt].ls, tree[x.rt].rs);
if (x.rt) q.push(trans(x.rt, x.v));
}
std::cout << ans << std::endl;
return 0;
}

K 短路的更多相关文章

  1. POJ 2449 Remmarguts' Date --K短路

    题意就是要求第K短的路的长度(S->T). 对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度. 但是这种方法效率太低,会扩展出很多状态,所以 ...

  2. POJ 2449Remmarguts' Date K短路模板 SPFA+A*

    K短路模板,A*+SPFA求K短路.A*中h的求法为在反图中做SPFA,求出到T点的最短路,极为估价函数h(这里不再是估价,而是准确值),然后跑A*,从S点开始(此时为最短路),然后把与S点能达到的点 ...

  3. BZOJ-1975 魔法猪学院 K短路 (A*+SPFA)

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1323 Solved: 433 [Submit][Statu ...

  4. 【POJ】2449 Remmarguts' Date(k短路)

    http://poj.org/problem?id=2449 不会.. 百度学习.. 恩. k短路不难理解的. 结合了a_star的思想.每动一次进行一次估价,然后找最小的(此时的最短路)然后累计到k ...

  5. poj 2449 Remmarguts' Date K短路+A*

    题目链接:http://poj.org/problem?id=2449 "Good man never makes girls wait or breaks an appointment!& ...

  6. 第k短路

    poj 2449 模板题  A*+spfa #include<iostream> #include<cstdio> #include<cstring> #inclu ...

  7. poj 2449(A*求第K短路)

    题目链接:http://poj.org/problem?id=2449 思路:我们可以定义g[x]为源点到当前点的距离,h[x]为当前点到目标节点的最短距离,显然有h[x]<=h*[x](h*[ ...

  8. K短路

    K短路 用dijsktra+A*启发式搜索当点v第K次出堆的时候,这时候求得的路径是k短路.A*算法有一个启发式函数f(p)=g(p)+h(p), 即评估函数=当前值+当前位置到终点的最短距离g(p) ...

  9. poj 2449 Remmarguts' Date(第K短路问题 Dijkstra+A*)

    http://poj.org/problem?id=2449 Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Subm ...

  10. bzoj 1975 [Sdoi2010]魔法猪学院(k短路)

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

随机推荐

  1. Codeforces 1236C. Labs

    传送门 注意到 $f(X,Y)+f(Y,X)$ 是一个定值(因为每个元素都不相同) 所以如果能让 $f(X,Y)$ 与 $f(Y,X)$ 尽可能接近,那么一定是最优的 所以可以这样构造:把 $n^2$ ...

  2. Codeforces 1238F. The Maximum Subtree

    传送门 考虑构造一些区间使得树尽可能的 "大" 发现这棵树最多就是一条链加上链上出去的其他边连接的点 构造的区间大概长这样(图比较丑请谅解..$qwq$,图中每一个 "└ ...

  3. Centos7.3安装Oracle11.2.0.3

    1.创建用户用户组 [root@smallcloud ~]# groupadd oinstall [root@smallcloud ~]# groupadd dba [root@smallcloud ...

  4. JSON函数表1

    jsoncpp 主要包含三个class:Value.Reader.Writer.注意Json::Value 只能处理 ANSI 类型的字符串,如果 C++ 程序是用 Unicode 编码的,最好加一个 ...

  5. 基于SQL Server日志链查看数据库insert/update/delete操作(一)

    在MSSQLServer2008下的语句 不同版本可能语句会有微小差别 SELECT [Slot ID], [Transaction ID], Operation, AllocUnitName, [C ...

  6. python对比线程,进程,携程,异步,哪个快

    目录概念介绍测试环境开始测试测试[单进程单线程]测试[多进程 并行]测试[多线程 并发]测试[协程 + 异步]结果对比绘图展示概念介绍首先简单介绍几个概念: 进程和线程进程就是一个程序在一个数据集上的 ...

  7. 深入理解hive之事务处理

    事务的四个特性 1.automicity:原子性 2.consistency:一致性 3. isolation:独立性 4.durability:持久性 5.支持事务有几个条件需要满足:1.所有的事务 ...

  8. javascript的特点这些

    javascript的特点(1)用于解释性执行的脚本语言.与其他脚本语言一样,JavaScript也是一种解释性语言,它提供了非常方便的开发过程.JavaScript的基本语法结构与C.C++.Jav ...

  9. 【Git的基本操作十】远程库分支操作

    远程库分支操作 1. 推送分支 在本地库新建分支 git branch [新分支名] 如创建一个develop分支: git branch develop 推送分支(将新分支发布在github上) g ...

  10. HWADDR配置错误导致network重启失败处理

    如果因为/etc/sysconfig/network-scripts/下的ifcfg-eth0(此处以eth0网卡名为例),其中的HWADDR配置错误,不知道到哪里找到原来的HWADDR时,可以尝试一 ...