LuoguP1710 地铁涨价
看到这个题,我们发现并不好维护删边。似乎我们删掉一条边,就得重建一次图。
那怎么避免这个呢。
我们可以删边的过程看做一个倒序加边的过程。
那么问题就转换成了:给定一个图,不断加边,求每个点到终点的最短路,成为最终图最短路的时间。
那么我们首先跑一遍最短路。然后重建图,倒序加边。
当一个点已经成为最短路点,那么入队(看是否可以松弛其他未成为路的点)。
可以发现,每个点至多被遍历一次,所以复杂度是可以接受的。
这种反向思维方式还是很有意思的。
#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#define RG register
#define Mkp make_pair
using namespace std;
inline int gi () {
int x=0,w=0; char ch=0;
while (!(ch>='0' && ch<='9')) ch=getchar ();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48), ch=getchar ();
return w?-x:x;
}
const int N=1e5+10;
const int M=2e5+10;
priority_queue <pair <int,int> > que;
int tot,head[N],Next[M<<1],to[M<<1];
int n,m,q,cnt,u[M],v[M],vis[N],dis[N],ans[M],tag[N],qq[M],qur[M],Ans[M];
inline void Make (int from, int To) {
Next[++tot]=head[from];
head[from]=tot;
to[tot]=To;
}
inline void Clear_ () {
tot=0;
memset (to, 0, sizeof (to));
memset (head, 0, sizeof (head));
memset (Next, 0, sizeof (Next));
}
void Dijkstra () {
RG int i,x,y;
memset (vis, 0, sizeof (vis));
memset (dis, 0x3f, sizeof (dis));
dis[1]=0; que.push (Mkp (0, 1));
while (!que.empty ()) {
x=que.top ().second; que.pop ();
if (vis[x]) continue;
vis[x]=1;
for (i=head[x];i;i=Next[i]) {
y=to[i];
if (dis[y]>dis[x]+1)
dis[y]=dis[x]+1, que.push (Mkp (-dis[y], y));
}
}
}
void DFS (int x, int fx) {
RG int i,y;
dis[x]=ans[fx]+1, tag[x]=0, cnt--;
for (i=head[x];i;i=Next[i]) {
y=to[i];
if (y==fx) continue;
if (ans[y]==dis[x]+1 && tag[y]) DFS (y, x);
}
}
int main ()
{
RG int i;
n=gi (), m=gi (), q=gi ();
for (i=1;i<=m;++i) {
u[i]=gi (), v[i]=gi ();
Make (u[i], v[i]), Make (v[i], u[i]);
}
Dijkstra (); Clear_ ();
for (i=1;i<=n;++i) ans[i]=dis[i];
for (i=1;i<=q;++i) qur[i]=gi (), qq[qur[i]]=1;
for (i=1;i<=m;++i) {
if (qq[i]) continue;
Make (u[i], v[i]), Make (v[i], u[i]);
}
Dijkstra ();
for (i=1;i<=n;++i)
if (dis[i]>ans[i]) tag[i]=1, cnt++;
for (i=q;i;--i) {
Ans[i]=cnt;
RG int a=u[qur[i]],b=v[qur[i]];
if (ans[a]==dis[a] && dis[a]+1==ans[b] && tag[b]) DFS (b, a);
if (ans[b]==dis[b] && dis[b]+1==ans[a] && tag[a]) DFS (a, b);
Make (a, b), Make (b, a);
}
for (i=1;i<=q;++i) printf ("%d\n", Ans[i]);
return 0;
}