[做题笔记] 那些未曾谋面的省选题
作者:互联网
我的博客大概要封笔了,最后一周也不会做什么题了,再见了朋友们。
[HNOI2014] 道路堵塞
题目描述
解法
我们不妨考虑增量法,先把在最短路径上的边排除掉,跑完最短路之后再慢慢添加边。
如果我们要求删除边 \(i\) 的答案,那么我们需要添加边 \([1,i)\),并且考虑 \((i,k]\) 边的影响(这些边我们是不加的),考虑把 \((i,k]\) 构成的路径染色,那么如果我们到达的某个点被染色,那么可以直接走最短路到终点。
为了保证复杂度我们把给定的最短路径染色,如果现在 \(\tt spfa\) 更新到了最短路上的第 \(i\) 个点,那么我们这条路径打上时间戳 \(i\),如果删除的边 \(\in(i,k]\),那么这条拼凑出来的路径是对答案有贡献的,用一个堆维护即可。
时间复杂度基于 \(\tt spfa\),所以在不刻意卡的情况是可以通过的。
还有一种时间复杂度稳定的最短路树做法,找机会填坑。
总结
图论中的一些动态算法十分重要,巧用动态算法可以快速完成版本之间的转化,以解决一维偏序关系。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int M = 200005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,tot,f[M],id[M],d[M],in[M];
queue<int> q;int rd[M],p[M],g[M],ban[M];
struct edge{int v,c,next;}e[M];
struct node
{
int u,c;
bool operator < (const node &b) const
{return c>b.c;}
};priority_queue<node> s;
void spfa(int now)
{
q.push(now);in[now]=1;
while(!q.empty())
{
int u=q.front();q.pop();in[u]=0;
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v,c=e[i].c;
if(ban[i]) continue;
if(d[v]>d[u]+c)
{
d[v]=d[u]+c;
if(id[v]) s.push({id[v],d[v]+g[id[v]]});
else if(!in[v]) in[v]=1,q.push(v);
}
}
}
}
signed main()
{
n=read();m=read();k=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read();
e[++tot]=edge{v,c,f[u]},f[u]=tot;
}
for(int i=1;i<=k;i++)
{
rd[i]=read();ban[rd[i]]=1;
p[i+1]=e[rd[i]].v;id[p[i+1]]=i+1;
}
p[1]=1;id[1]=1;
for(int i=k;i>=1;i--) g[i]=g[i+1]+e[rd[i]].c;
memset(d,0x3f,sizeof d);
d[1]=0;spfa(1);
for(int i=1;i<=k;i++)
{
while(!s.empty() && s.top().u<=i) s.pop();
if(s.empty()) puts("-1");
else printf("%d\n",s.top().c);
d[p[i+1]]=d[p[i]]+e[rd[i]].c;
spfa(p[i+1]);
}
}
标签:选题,const,谋面,int,路径,笔记,read,spfa,include 来源: https://www.cnblogs.com/C202044zxy/p/16063441.html