题意:给出一个无向图,给定起点和终点。给出q个询问,每个询问是删除某条边之后,起点到终点的最短路变成什么?询问之间是独立的。
这道题不错,但是蒟蒻完全不会做qaq,解法参考Claris大佬的。
首先容易想到如果删掉的边不在最短路上的话,最短路是不会变的。于是我们先跑一遍最短路,找出一条最短路。
终点是如果删掉最短路上的边怎么办?
这里我们反过来考虑,我们考虑,每一条非最短路边对最短路的贡献。首先分别以S和T为起点做一遍最短路记为d1[i]和d2[i],同时随便抓一条最短路Path并把它编号。
在以S为起点的最短路图,这必定是一个DAG,我们计算f1[i]代表(最早的)(在最短路Path上的)(能到达i点)的点是谁?
同理以T为起点的最短路图,我们计算f2[i]代表(最晚的)(在最短路Path上的)(能到达i点)的点是谁?
以上两个信息可以用拓扑排序DP计算得到。
那么对于每一条非最短路Path的边(x,y),它的贡献是什么:对于当区间 [ f1[x],f2[y] ]的边被删除时,边(x,y)能提供一条长度为d1[x]+len(x,y)+d2[y]的最短路,这里要注意所谓贡献,并不是只要删掉区间
[ f1[x],f2[y] ]的边,d1[x]+len(x,y)+d2[y] 就是答案,贡献的意思是这可以作为一种选择,并且这个选择是所有基于边(x,y)中最好的,因为d1[x]是正向最短路,d2[y]是反向最短路。
由上面这段路就得出做法了,我们用线段树维护这些所有选择,并选择最短的,这就是答案。
细节看代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const LL N=4e5+10; const LL INF=0x3f3f3f3f3f3f3f3f; LL n,m,s,t,T,x[N],y[N],z[N],id[N],deg[N]; vector<LL> G[N]; LL tot,d1[N],d2[N],pre[N],path[N],f1[N],f2[N]; LL cnt=1,head[N],to[N<<1],nxt[N<<1],len[N<<1]; void add_edge(LL x,LL y,LL z) { nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt; } bool vis[N]; priority_queue<pii> q; void Dijkstra(LL d[],LL s) { while (!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); d[s]=0; q.push(make_pair(0,s)); while (!q.empty()) { pii x=q.top(); q.pop(); if (vis[x.second]) continue; vis[x.second]=1; for (LL i=head[x.second];i;i=nxt[i]) { LL y=to[i]; if (d[y]>d[x.second]+len[i]) { d[y]=d[x.second]+len[i]; q.push(make_pair(-d[y],y)); } } } } queue<LL> Q; void toposort(LL f[],LL now) { while (!Q.empty()) Q.pop(); Q.push(now); while (!Q.empty()) { LL x=Q.front(); Q.pop(); if (id[x]) f[x]=id[x]; for (LL i=0;i<G[x].size();i++) { LL y=G[x][i]; if (now==s) f[y]=min(f[y],f[x]); if (now==t) f[y]=max(f[y],f[x]); if (--deg[y]==0) Q.push(y); } } } LL Min[N<<2],tag[N<<2]; void build(LL rt,LL l,LL r) { Min[rt]=tag[rt]=INF; if (l==r) return; LL mid=l+r>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void pushdown(LL rt) { Min[rt<<1]=min(Min[rt<<1],tag[rt]); Min[rt<<1|1]=min(Min[rt<<1|1],tag[rt]); tag[rt<<1]=min(tag[rt<<1],tag[rt]); tag[rt<<1|1]=min(tag[rt<<1|1],tag[rt]); tag[rt]=INF; } void update(LL rt,LL l,LL r,LL ql,LL qr,LL v) { if (ql<=l && r<=qr) { Min[rt]=min(Min[rt],v),tag[rt]=min(tag[rt],v); return; } LL mid=l+r>>1; pushdown(rt); if (ql<=mid) update(rt<<1,l,mid,ql,qr,v); if (qr>mid) update(rt<<1|1,mid+1,r,ql,qr,v); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } LL query(LL rt,LL l,LL r,LL ql,LL qr) { if (ql<=l && r<=qr) return Min[rt]; LL mid=l+r>>1,ret=INF; pushdown(rt); if (ql<=mid) ret=min(ret,query(rt<<1,l,mid,ql,qr)); if (qr>mid) ret=min(ret,query(rt<<1|1,mid+1,r,ql,qr)); return ret; } bool onpath(LL x,LL y) { if (!id[x] || !id[y]) return 0; if (id[x]+1==id[y] || id[y]+1==id[x]) return 1; return 0; } int main() { //freopen("in.txt","r",stdin); //freopen("out2.txt","w",stdout); cin>>n>>m; for (LL i=1;i<=m;i++) { scanf("%lld%lld%lld",&x[i],&y[i],&z[i]); add_edge(x[i],y[i],z[i]); add_edge(y[i],x[i],z[i]); } cin>>s>>t; cin>>T; if (s==t) { for (LL i=1;i<=T;i++) puts("0"); return 0; } memset(d1,0x3f,sizeof(d1)); Dijkstra(d1,s); if (d1[t]>=INF) { for (LL i=1;i<=T;i++) puts("Infinity"); return 0; } memset(d2,0x3f,sizeof(d2)); Dijkstra(d2,t); memset(deg,0,sizeof(deg)); for (LL i=1;i<=m;i++) { if (d1[x[i]]+z[i]==d1[y[i]]) G[x[i]].push_back(y[i]),deg[y[i]]++,pre[y[i]]=x[i]; if (d1[y[i]]+z[i]==d1[x[i]]) G[y[i]].push_back(x[i]),deg[x[i]]++,pre[x[i]]=y[i]; } for (LL i=t;i;i=pre[i]) path[++tot]=i,id[i]=tot; for (LL i=1;i<=n;i++) if (id[i]) id[i]=tot-id[i]+1; memset(f1,0x3f,sizeof(f1)); toposort(f1,s); memset(deg,0,sizeof(deg)); for (LL i=1;i<=n;i++) G[i].clear(); for (LL i=1;i<=m;i++) { if (d2[x[i]]+z[i]==d2[y[i]]) G[x[i]].push_back(y[i]),deg[y[i]]++; if (d2[y[i]]+z[i]==d2[x[i]]) G[y[i]].push_back(x[i]),deg[x[i]]++; } memset(f2,0,sizeof(f2)); toposort(f2,t); tot--; build(1,1,tot); for (LL i=1;i<=m;i++) if (!onpath(x[i],y[i])) { LL t1=f1[x[i]],t2=f2[y[i]]; t2--; if (t1<INF&&t2>0&&t1<=t2) update(1,1,tot,t1,t2,d1[x[i]]+d2[y[i]]+z[i]); t1=f1[y[i]],t2=f2[x[i]]; t2--; if (t1<INF&&t2>0&&t1<=t2) update(1,1,tot,t1,t2,d1[y[i]]+d2[x[i]]+z[i]); } while (T--) { LL x,y; scanf("%lld%lld",&x,&y); if (!onpath(x,y)) printf("%lld\n",d1[t]); else { x=id[x]; y=id[y]; if (x>y) swap(x,y); y--; LL ans=query(1,1,tot,x,y); if (ans>=INF) puts("Infinity"); else printf("%lld\n",ans); } } return 0; }