题面

题解

解法一

这个思路要基于以下一个结论:

当你删掉某条边\((x,x+1)\)时,最短路路线为:\(1\to x(\leq u)\to y(>u) \to n\),并且\(x\to y\)一定不会属于原最短路。

我们枚举删掉最短路上的哪条边,然后把这条边的\(s\)加进队列做SPFA,这个应该就是部分分。

优化:先把最短路上的所有边都删掉,然后从\(S\)到\(T\)开始恢复边,并把\(s\)丢进队列。然后每次就可以不清空\(dis\)数组了,因为你之前SPFA的结果你都可以调用以前的结果。

然后统计答案就是把走到的钦定最短路上的点的距离加上它到\(T\)的距离取个\(\min\)就好了,这个用堆就可以了。

时间复杂度\(\mathrm{O}(\mathrm{spfa})\)

而\(\mathrm{spfa}\)的复杂度是无法保证的,所以这个方法是假的。

解法二

分别从起点和终点开始求最短路图,可以证明删去一条边之后的最短路最多只会有一条边不在最短路图上。

设给出的最短路为\(v_1, v_2, \cdots, v_l\)。

枚举每条边\((a, b)\),那么经过这条边的最短路一定是形如

\(v_1 \to v_2 \to \cdots \to v_i \to \cdots \to a \to b \to \cdots \to v_j \to \cdots \to v_l\),找出满足条件的最小的\(i\)和最大的\(j\),

那么如果删去的边是\(v_i \to v_j\)的边,那么都可以用这条路径来替代。

于是就变成了区间取\(\min\),询问每一条边的值,用线段树即可。

时间复杂度\(\mathrm{O}(n \log_2n)\)

代码

解法一

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x)) inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
} const int maxn(200010), maxm(1000010);
struct edge { int next, to, dis; } e[maxm];
int head[maxn], e_num, n, m, L, vis[maxn];
int blk[maxn], sp[maxn], s[maxn], from[maxn];
int g[maxn], dis[maxn]; struct node { int to, val; };
inline bool operator < (const node &lhs, const node &rhs)
{ return lhs.val > rhs.val; }
std::priority_queue<node> heap; inline void add_edge(int from, int to, int dis)
{
e[++e_num] = (edge) {head[from], to, dis};
head[from] = e_num;
} void spfa(int S)
{
std::queue<int> q; q.push(S), vis[S] = 1;
while(!q.empty())
{
int x = q.front(); q.pop(); vis[x] = 0;
for(RG int i = head[x]; i; i = e[i].next)
{
if(blk[i]) continue;
int to = e[i].to;
if(dis[to] > dis[x] + e[i].dis)
{
dis[to] = dis[x] + e[i].dis;
if(from[to]) heap.push((node)
{from[to], dis[to] + g[from[to]]});
else if(!vis[to]) q.push(vis[to] = to);
}
}
}
} int main()
{
n = read(), m = read(), L = read();
for(RG int i = 1, a, b, c; i <= m; i++)
a = read(), b = read(), c = read(),
add_edge(a, b, c);
for(RG int i = 1; i <= L; i++)
{
sp[i] = read(), blk[sp[i]] = 1;
from[s[i + 1] = e[sp[i]].to] = i + 1;
}
for(RG int i = L; i; i--) g[i] = g[i + 1] + e[sp[i]].dis;
memset(dis, 0x3f, sizeof dis);
dis[from[1] = s[1] = 1] = 0, spfa(1);
for(RG int i = 1; i <= L; i++)
{
while(!heap.empty() && heap.top().to <= i) heap.pop();
if(heap.empty()) puts("-1"); else printf("%d\n", heap.top().val);
dis[e[sp[i]].to] = dis[s[i]] + e[sp[i]].dis, spfa(s[i + 1]);
}
return 0;
}

解法二

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<algorithm>
#include<queue>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x)) inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
} const int maxn(100010);
struct edge { int next, to; } e[maxn << 1];
int n, m, L, min[maxn << 2], head[maxn], e_num, vis[maxn];
std::pair<int, int> dis[2][maxn];
typedef std::pair<std::pair<int, int>, int> pair; inline void add_edge(int from, int to)
{
e[++e_num] = (edge) {head[from], to};
head[from] = e_num;
} struct node { int x, y, dis, opt; } E[maxn << 1];
std::priority_queue<pair, std::vector<pair>, std::greater<pair> > Q;
void Dijkstra(int S, int opt, int T)
{
Q.push(std::make_pair(dis[opt][S], S));
memset(vis, 0, sizeof vis);
for(RG int i = 1; i <= n; i++) if(E[i].opt)
Q.push(std::make_pair(dis[opt][E[i].y], E[i].y));
while(!Q.empty())
{
int x = Q.top().second; Q.pop();
if(vis[x] || x == T) continue;
vis[x] = 1;
for(RG int i = head[x]; i; i = e[i].next)
{
if(E[i].opt) continue;
std::pair<int, int> t =
std::make_pair(dis[opt][x].first + E[i].dis, dis[opt][x].second);
if(t < dis[opt][E[i].y]) dis[opt][E[i].y] = t,
Q.push(std::make_pair(t, E[i].y));
}
}
} void build(int root = 1, int l = 1, int r = L)
{
min[root] = INT_MAX; if(l == r) return;
int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
build(lson, l, mid); build(rson, mid + 1, r);
} void modify(int ql, int qr, int v, int root = 1, int l = 1, int r = L)
{
if(ql <= l && r <= qr) return (void)(min[root] = std::min(min[root], v));
int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
if(ql <= mid) modify(ql, qr, v, lson, l, mid);
if(mid < qr) modify(ql, qr, v, rson, mid + 1, r);
} int query(int pos, int root = 1, int l = 1, int r = L)
{
if(l == r) return min[root];
int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
if(pos <= mid) return std::min(min[root], query(pos, lson, l, mid));
else return std::min(min[root], query(pos, rson, mid + 1, r));
} int main()
{
#ifndef ONLINE_JUDGE
file(cpp);
#endif
n = read(), m = read(), L = read();
for(RG int i = 1, a, b, c; i <= m; i++)
a = read(), b = read(), c = read(),
E[i] = (node) {a, b, c, 0}, add_edge(a, b);
for(RG int i = 1; i <= n; i++)
dis[0][i] = dis[1][i] = std::make_pair(INT_MAX >> 1, 0);
dis[0][1] = dis[1][n] = std::make_pair(0, 0);
for(RG int i = 1, x; i <= L; i++)
{
E[x = read()].opt = 1;
dis[0][E[x].y].first = dis[0][E[x].x].first + E[x].dis;
dis[1][E[x].y].second = -(dis[0][E[x].y].second = i);
}
for(RG int i = 1; i <= m; i++) if(E[i].opt)
dis[1][E[i].x].first = dis[0][n].first - dis[0][E[i].x].first;
Dijkstra(1, 0, n); memset(head, 0, sizeof head); e_num = 0;
for(RG int i = 1; i <= m; i++)
std::swap(E[i].x, E[i].y), add_edge(E[i].x, E[i].y);
Dijkstra(n, 1, 1); for(RG int i = 1; i <= m; i++) std::swap(E[i].x, E[i].y);
for(RG int i = 1; i <= n; i++) dis[1][i].second *= -1;
build();
for(RG int i = 1; i <= m; i++)
{
if(E[i].opt) continue;
std::pair<int, int> x = dis[0][E[i].x], y = dis[1][E[i].y];
if(x.second < y.second) modify(x.second + 1, y.second,
x.first + y.first + E[i].dis);
}
for(RG int i = 1; i <= L; i++)
{
int now = query(i); if(now >= (1 << 30)) now = -1;
printf("%d\n", now);
}
return 0;
}

【HNOI2014】道路堵塞的更多相关文章

  1. 洛谷 [HNOI2014]道路堵塞 解题报告

    [HNOI2014]道路堵塞 题意 给一个有向图并给出一个这个图的一个\(1\sim n\)最短路,求删去这条最短路上任何一条边后的最短路. 又事SPFA玄学... 有个结论,新的最短路一定是\(1\ ...

  2. 动态删边SPFA: [HNOI2014]道路堵塞

    [HNOI2014]道路堵塞 题目描述 $A$ 国有 $N$座城市,依次标为$1$到$N$.同时,在这$N$座城市间有$M$条单向道路,每条道路的长度是一个正整数.现在,$A$国交通部指定了一条从城市 ...

  3. bzoj 3575: [Hnoi2014]道路堵塞

    Description A 国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所 ...

  4. [HNOI2014]道路堵塞

    题目描述 A国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径,并且保证这条路径的长度是所有从城市1到城市N ...

  5. bzoj3575[Hnoi2014]道路堵塞

    http://www.lydsy.com/JudgeOnline/problem.php?id=3575 总赶脚第二题总是比第三题难...... 好吧,这题一点思路都没有 听说用民科可以过掉大部分数据 ...

  6. luogu P3238 [HNOI2014]道路堵塞

    传送门 这什么题啊,乱搞就算了,不知道SPFA已经死了吗 不对那个时候好像还没死 暴力就是删掉边后跑Dijkstra SPFA 然后稍微分析一下,可以发现题目中要求的不经过最短路某条边的路径,一定是先 ...

  7. BZOJ.3575.[HNOI2014]道路堵塞(最短路 动态SPFA)

    题目链接 \(Description\) 给你一张有向图及一条\(1\)到\(n\)的最短路.对这条最短路上的每条边,求删掉这条边后\(1\)到\(n\)的最短路是多少. \(Solution\) 枚 ...

  8. 【BZOJ】3575: [Hnoi2014]道路堵塞

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3575 大概的做法是,按照顺序枚举每一条要删去的边,(假设当前点为$u$,在最短路径上的下一 ...

  9. 【bzoj3575】 Hnoi2014—道路堵塞

    http://www.lydsy.com/JudgeOnline/problem.php?id=3575 (题目链接) 题意 给出一个有向图和一条最短路,问最短路上任意一条边断掉,此时的最短路是多少. ...

  10. 【LG3238】 [HNOI2014]道路堵塞

    题目描述 给你一张\(N\)个点.\(M\)条边的有向图,按顺序给定你一条有\(L\)条边的\(1\rightarrow n\)的最短路, 每次断掉这\(L\)条边中的一条(不对后面答案产生影响),求 ...

随机推荐

  1. 远程监视jboss应用java内存的配置

    前言 因为最近一个项目部署在客户那边运行一个月左右就会出现java内存溢出的问题,为了时时监控java内存的情况需要,需要远程查看服务器上java内存的一些情况.在公司模拟部署了远程监视linux下项 ...

  2. 【Redis】命令学习笔记——列表(list)+集合(set)+有序集合(sorted set)(17+15+20个超全字典版)

    本篇基于redis 4.0.11版本,学习列表(list)和集合(set)和有序集合(sorted set)相关命令. 列表按照插入顺序排序,可重复,可以添加一个元素到列表的头部(左边)或者尾部(右边 ...

  3. 选中复选框,才能在文本框中输东西。button按钮已启用,

  4. MySQL Flashback 工具介绍

    MySQL Flashback 工具介绍 DML Flashback 独立工具,通过伪装成slave拉取binlog来进行处理 MyFlash 「大众点点评」 binlog2sql 「大众点评(上海) ...

  5. hibernate连接mysql,查询条件中有中文时,查询结果没有记录,而数据库有符合条件的记录(解决方法)

    今天在另一台服务器上重新部署了网站,结果出现了以下问题: ——用hibernate做mysql的数据库连接时,当查询条件中有中文的时候,查询结果没有记录,而数据库中是存在符合条件的记录的. 测试了以下 ...

  6. 第八章 计时器(BEEPER2)

    /*------------------------------------- BEEPER2.C -- Timer Demo Program No.1 (c) Charles Petzold, 19 ...

  7. 关于strip(切割)和 split(分开) 的区别

    plit(), 以括号里的东西为标准,把字符串分开成一个列表 strip(), "删除",括号里出现的东西,从两头开始往中间删除,直到遇到阻碍.中间就算有,也不会受影响 s10 = ...

  8. ubuntu 14.04 安装 openvswitch

    安装 openvswitch (这里以openvswitch lib 分支为例) 如果没有安装git,如果有请跳过 $ sudo apt-get install git install ovs $ g ...

  9. [转]JMX的Hello World

    这篇写的很详尽了: http://www.blogjava.net/hengheng123456789/articles/65690.html

  10. Android 高级UI设计笔记24:Android 夜间模式之 WebView 实现白天 / 夜间阅读模式 (使用JavaScript)

    1. 问题引入: 前面我们是使用方法 降低屏幕亮度(不常用) 和 替换theme,两者都是针对Activity的背景进行白天.夜间模式的交换,但是如果我们显示的是Html的内容,这个时候改怎么办? 分 ...