Luogu2483 [SDOI2010]魔法猪学院(可并堆)
对于原图以 \(t\) 为根建出任意一棵最短路径树 \(T\),即反着从 \(t\) 跑出到所有点的最短路 \(dis\)
它有一些性质:
性质1:
对于一条 \(s\) 到 \(t\) 的路径的边集 \(P\),去掉 \(P\) 中和 \(T\) 的交集,记为 \(P'\)。
那么 \(P'\) 对于中任意相邻(从 \(s\) 到 \(t\) 的顺序)的两条边 \(e,f\),满足 \(f\) 的起点在 \(T\) 中为 \(e\) 的终点的祖先或者为相同点。
因为 \(P\) 中 \(e,f\) 之间由树边相连或者直接相连。
性质2:
对于不在 \(T\) 中的边 \(e\) ,设 \(u\) 为起点,\(v\) 为终点,\(w\)为权值。
定义 \(\Delta_e=dis_v+w-dis_u\),即选这条边的路径和最短路的长度的差
设 \(L_P\) 表示路径长度,则有
\]
这很显然。
性质3:
对于满足性质 \(1\) 的 \(P'\)的定义的边集 \(S\),有且仅有一条 \(s\) 到 \(t\) 的路径的边集 \(P\),使得 \(P'=S\)。
因为树 \(T\) 上的两个点之间有且仅有一条路径。
问题转化
求第 \(k\) 小的满足性质 \(1\) 的 \(P'\)的定义的边集
算法
用小根堆维护边集 \(P\)
初始 \(P\) 为空集(实际上只要维护边集当前尾部的边的起点是哪一个就好了,空集即 \(s\))
每次取出最小权值的边集 \(P\),设当前尾部的边的起点为 \(x\)
有两种方法可以得到一个新的边集:
1.替换 \(x\) 为起点的这条边为一条刚好大于等于它的非树边。
2.尾部接上一条起点为以 \(x\) 为起点的这条边的终点在 \(T\) 中祖先(包括自己)连出去的所有非树边的最小边。
然后就是怎么维护祖先出去的所有非树边的最小边:
显然可以从祖先转移过来,直接可并堆即可。
又因为要保留每个点的信息,所以合并的时候可持久化即可
和线段树合并的可持久化一样,然后就可以过了。
建议可以看一看课件
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template <class Num> inline void Cmax(Num &x, const Num y) {
x = y > x ? y : x;
}
template <class Num> inline void Cmin(Num &x, const Num y) {
x = y < x ? y : x;
}
const int maxn(5005);
const int maxm(2e5 + 5);
const double eps(1e-8);
int n, m, first[maxn], cnt, vis[maxn], rt[maxn], tot, cov[maxm << 1], ans, fa[maxn];
double se, e, dis[maxn];
priority_queue < pair <double, int> > q;
struct Heap {
int ls, rs, dis, ed;
double w;
} tr[maxm * 20];
struct Edge {
int to, next;
double w;
} edge[maxm << 1];
inline void Add(int u, int v, double w) {
edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
edge[cnt] = (Edge){u, first[v], w}, first[v] = cnt++;
}
inline int NewNode(double w, int ed) {
int x = ++tot;
tr[x].w = w, tr[x].dis = 1, tr[x].ed = ed;
return x;
}
int Merge(int x, int y) {
if (!x || !y) return x + y;
if (tr[x].w - tr[y].w >= eps) swap(x, y);
int p = ++tot;
tr[p] = tr[x], tr[p].rs = Merge(tr[p].rs, y);
if (tr[tr[p].ls].dis < tr[tr[p].rs].dis) swap(tr[p].ls, tr[p].rs);
tr[p].dis = tr[tr[x].rs].dis + 1;
return p;
}
void Dfs(int u) {
vis[u] = 1;
for (int e = first[u], v; e != -1; e = edge[e].next)
if (e & 1) {
double w = edge[e].w;
if (fabs(dis[u] + w - dis[v = edge[e].to]) < eps && !vis[v])
fa[v] = u, cov[e ^ 1] = 1, Dfs(v);
}
}
int main() {
memset(first, -1, sizeof(first));
memset(dis, 127, sizeof(dis));
scanf("%d%d%lf", &n, &m, &se);
for (int i = 1, u, v; i <= m; ++i) scanf("%d%d%lf", &u, &v, &e), Add(u, v, e);
dis[n] = 0, q.push(make_pair(0, n));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int e = first[u]; ~e; e = edge[e].next)
if (e & 1) {
int v = edge[e].to;
if (dis[v] - (dis[u] + edge[e].w) >= eps)
q.push(make_pair(-(dis[v] = dis[u] + edge[e].w), v));
}
}
for (int i = 1; i <= n; ++i) vis[i] = 0;
Dfs(n);
for (int e = 0, u, v; e < cnt; e += 2)
if (!cov[e]) {
u = edge[e ^ 1].to, v = edge[e].to;
if (dis[u] == dis[0] || dis[v] == dis[0]) continue;
rt[u] = Merge(rt[u], NewNode(dis[v] + edge[e].w - dis[u], v));
}
for (int i = 1; i <= n; ++i) q.push(make_pair(-dis[i], i));
for (int i = 1, u; i <= n; ++i) {
u = q.top().second, q.pop();
if (fa[u]) rt[u] = Merge(rt[u], rt[fa[u]]);
}
if (dis[1] - se < eps) se -= dis[1], ++ans;
if (rt[1]) q.push(make_pair(-tr[rt[1]].w, rt[1]));
while (!q.empty()) {
int ed = q.top().second;
double cur = q.top().first, w = dis[1] - cur;
if (w - se >= eps) break;
q.pop(), se -= w, ++ans;
for (int i = 0; i < 2; ++i) {
int nxt = i ? tr[ed].rs : tr[ed].ls;
if (nxt) q.push(make_pair(cur + tr[ed].w - tr[nxt].w, nxt));
}
if (rt[tr[ed].ed]) q.push(make_pair(cur - tr[rt[tr[ed].ed]].w, rt[tr[ed].ed]));
}
printf("%d\n", ans);
return 0;
}
Luogu2483 [SDOI2010]魔法猪学院(可并堆)的更多相关文章
- Bzoj 1975: [Sdoi2010]魔法猪学院 dijkstra,堆,A*,K短路
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1357 Solved: 446[Submit][Statu ...
- BZOJ_1975_[Sdoi2010]魔法猪学院_A*
BZOJ_1975_[Sdoi2010]魔法猪学院_A* Description iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPi ...
- K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院
A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...
- [BZOJ1975][SDOI2010]魔法猪学院(k短路,A*)
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2748 Solved: 883[Submit][Statu ...
- bzoj 1975: [Sdoi2010]魔法猪学院 [k短路]
1975: [Sdoi2010]魔法猪学院 裸题... 被double坑死了 #include <iostream> #include <cstdio> #include &l ...
- bzoj 1975 [Sdoi2010]魔法猪学院
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1758 Solved: 557[Submit][Statu ...
- P2483 [SDOI2010]魔法猪学院
P2483 [SDOI2010]魔法猪学院 摘要 --> 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世 ...
- 【BZOJ1975】[Sdoi2010]魔法猪学院 A*
[BZOJ1975][Sdoi2010]魔法猪学院 Description iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪 ...
- bzoj1975: [Sdoi2010]魔法猪学院【k短路&A*算法】
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2446 Solved: 770[Submit][Statu ...
随机推荐
- navicat for oracle 创建表ID字段的自动递增
Oracle数据库创建表ID字段的自动递增 将表t_uaer的字段ID设置为自增:(用序列sequence的方法来实现) ----创建表 Create table t_user( Id numbe ...
- 关于Mysql数据库查询数据大小写的问题汇总
前天在问答区看到一个童鞋对于mysql中大小写问题不熟悉,在回复他后再次汇总梳理如下: mysql中大小写问题主要有以下两种: A.表名区分大小写 ower_case_table_names 是表名区 ...
- Eclipse中的创建maven项目,无法添加src/main/java等source folder
maven无法添加src/main/java 通过Eclipse创建Java Web项目,目录结构如下: 默认是只有src/main/resources 这个source folder 按照maven ...
- Mysql备份之Innobakcupex&Xtrabackup
一.innobackupex备份工具 基本选项 --compress:该选项表示压缩innodb数据文件的备份. --compress-threads:该选项表示 ...
- switch case执行顺序
public class SwitchCase { public static void main(String[] args) { System.out.println(switchFun(4)); ...
- springcloud(五)-Ribbon
前言 先发句牢骚,最近太TM忙了,一直没时间静下心来继续写微服务架构!EMMMMMM..... 经过前文的讲解,我们已经实现了微服务的注册与发现.启动各个微服务时,Eureka Client会把自己的 ...
- 线段树+单调栈+前缀和--2019icpc南昌网络赛I
线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...
- R302指识别开发笔记
一.相关概念 1.存储容量:500枚指纹,地址范围0-499. 2.用户记事本:模块内部为用户开辟了512Bytes的FLASH空间用于存放用户数据该存储空间称为用户记事本,该记事本逻辑上被分成16个 ...
- 利用IDEA创建Web Service服务端和客户端的详细过程
创建服务端 一.file–>new–>project 二.点击next后输入服务端名,点击finish,生成目录如下 三.在 HelloWorld.Java 文件中右击,选 WebServ ...
- Android开源项目xUtils HttpUtils模块分析(转)
xUtils是github上的一个Android开源工具项目,其中HttpUtils模块是处理网络连接部分,刚好最近想整理下Android网络编程知识,今天学习下xUtils中HttpUtils. x ...