题面

题解

解法一

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

当你删掉某条边\((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. C# 标准的MD5加密32位

    标准的MD5加密32位小写的: public static string GetMD5(string myString) { MD5 md5 = new MD5CryptoServiceProvide ...

  2. iOS8中的定位服务

    iOS8中的定位服务 My app that worked fine in iOS 7 doesn't work with the iOS 8 SDK. CLLocationManager doesn ...

  3. Oracle Order By 排序 非主键时 紊乱 重复 问题

    Oracle的分页查询是没有进行任何排序操作的,Oracle是顺序的从数据块中读取符合条件的数据返回到客户端. 而Oracle的排序算法不具有稳定性,也就是说,对于排序键值相等的数据,这种算法完成排序 ...

  4. Linux 安装 pycharm

    1.Windows系统下载http://www.jetbrains.com/pycharm/download/#section=linux2.解压到挂载文件夹 mount -t cifs -o use ...

  5. November 13th 2016 Week 47th Sunday The 1st Day

    Adventure may hurt you, but monotony will kill you. 也许冒险会让你受伤,但一成不变会让你灭亡. Just change a bit, let the ...

  6. 新手指南:Linux上vi(vim)编辑器使用教程

    vi(vim)是上Linux非常常用的编辑器,很多Linux发行版都默认安装了vi(vim).vi(vim)命令繁多但是如果使用灵活之后将会大大提高效率.vi是“visual interface”的缩 ...

  7. css3动画效果小结

    css3的动画功能有以下三种: 1.transition(过度属性) 2.animation(动画属性) 3.transform(2D/3D转换属性) 下面逐一进行介绍我的理解: 1.transiti ...

  8. JavaScript中操作有些DOM时关于文本节点和元素节点的问题。

    初学JavaScript时候,经常遇到需要操作的内容因为文本节点而使操作更麻烦或者不能达到效果. 例: <ul id="ull">    <li>111&l ...

  9. JavaScript中烧脑的&&和||

    在js中经常能看到以下的写法: var obj1 = a || b || c; var obj2 = a && b && c; 刚看到时,很容易认为返回的两个变量都是 ...

  10. luogu P3391 【模板】文艺平衡树(Splay)

    嘟嘟嘟 突然觉得splay挺有意思的-- 这道题只有一个任务:区间翻转. 首先应该知道的是,splay和线段树一样,都可以打标记,然后走到每一个节点之前先下传. 那怎么打标记呢?还应该有"区 ...