[bzoj2725]故乡的梦——最短路+线段树
题目大意:
给定一个带权无向图,每次询问删除一条边之后从S到T的最短路是多少?(各个询问之间独立)
思路:
如果删除的边不在最短路中或者可以被替换,那么答案即为最短路。
如果删除的边在最短路中并且不可以被替换,考虑将这条边删除的新图:
假设原来的最短路为\(S->T\),那么新的最短路一定是\(S->u->x->y->v->T\)(其中u,v在原来的最短路上,x,y不在原来的最短路上)
于是我们发现如果删除了这条边之后S和T联通,那么一定会经过形如\(x->y\)这样的路径,即经过原本不在最短路中的边。
并且对于\(x->y\)中的一条边(uu,vv),\(S->uu\)和\(vv->T\)一定是两条最短的路径于是我们枚举出每一条不在最短路中的边(uu,vv),并计算出对应的最早的u和最晚的v,用强制经过(uu,vv)的最短路去更新u和v中间缺失的那些边的答案。为了方便,在具体实现的时候随意提出一条\(S->T\)的最短路并把它当作唯一的最短路即可。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<endl
#define pii pair<ll,int>
#define fi first
#define se second
#define mk make_pair
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj2725.in","r",stdin);
freopen("bzoj2725.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,q,ss,tt;
int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1;
ll w[maxn<<1],dis[maxn],ddis[maxn];
int pre[maxn],nex[maxn],pre_node[maxn],ls[maxn],cnt_ls,num[maxn],cnt_num;
int ps[maxn],pt[maxn];
map<int,int>mp[maxn];
void add(int u,int v,ll val){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; w[cnte]=val;
}
void Dijkstra_pre(){
priority_queue<pii,vector<pii>,greater<pii> >qu;
memset(dis,63,sizeof(dis));
dis[ss]=0; qu.push(mk(0,ss));
while(!qu.empty()){
int u=qu.top().se; ll d=qu.top().fi;
qu.pop();
if(dis[u]!=d)continue;
for(int i=beg[u];i;i=las[i]){
int v=to[i];
if(d+w[i]<dis[v]){
pre[v]=i/2;
pre_node[v]=u;
dis[v]=d+w[i];
qu.push(mk(dis[v],v));
}
}
}
int p=tt;
while(pre_node[p]){
num[pre[p]]=++cnt_num;
nex[pre_node[p]]=pre[p];
ls[++cnt_ls]=p;
p=pre_node[p];
}
ls[++cnt_ls]=ss;
REP(i,1,cnte/2)if(num[i])
num[i]=cnt_num-num[i]+1;
}
void Dijkstra1(){
priority_queue<pii,vector<pii>,greater<pii> >qu;
memset(ddis,63,sizeof(ddis));
REP(i,1,cnt_ls){
ddis[ls[i]]=dis[ls[i]];
qu.push(mk(ddis[ls[i]],ls[i]));
ps[ls[i]]=ls[i];
}
while(!qu.empty()){
int u=qu.top().se; ll d=qu.top().fi;
qu.pop();
if(ddis[u]!=d)continue;
for(int i=beg[u];i;i=las[i]){
int v=to[i];
if(d+w[i]<ddis[v]){
ps[v]=ps[u];
ddis[v]=d+w[i];
qu.push(mk(ddis[v],v));
}
else if(d+w[i]==ddis[v] && ps[v]!=v && ps[u]<ps[v])
ps[v]=ps[u];
}
}
}
void Dijkstra2(){
priority_queue<pii,vector<pii>,greater<pii> >qu;
memset(ddis,63,sizeof(ddis));
REP(i,1,cnt_ls){
ddis[ls[i]]=dis[tt]-dis[ls[i]];
qu.push(mk(ddis[ls[i]],ls[i]));
pt[ls[i]]=ls[i];
}
while(!qu.empty()){
int u=qu.top().se; ll d=qu.top().fi;
qu.pop();
if(ddis[u]!=d)continue;
for(int i=beg[u];i;i=las[i]){
int v=to[i];
if(d+w[i]<ddis[v]){
pt[v]=pt[u];
ddis[v]=d+w[i];
qu.push(mk(ddis[v],v));
}
else if(d+w[i]==ddis[v] && pt[v]!=v && pt[u]<pt[v])
pt[v]=pt[u];
}
}
}
void init(){
read(n); read(m);
int u,v; ll val;
REP(i,1,m){
read(u),read(v),read(val);
add(u,v,val); mp[u][v]=mp[v][u]=cnte/2;
}
read(ss); read(tt);
Dijkstra_pre();
Dijkstra1();
Dijkstra2();
}
struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
ll Min[maxn<<2];
void update(int rt,int l,int r,int L,int R,ll x){
if(L>R || !L || !R)return;
if(L<=l && r<=R)Min[rt]=min(Min[rt],x);
else{
if(L<=mid)update(lson,L,R,x);
if(R>=mid+1)update(rson,L,R,x);
}
}
ll query(int rt,int l,int r,int p){
if(l==r)return Min[rt];
if(p<=mid)return min(Min[rt],query(lson,p));
return min(Min[rt],query(rson,p));
}
}T;
void work(){
memset(T.Min,63,sizeof(T.Min));
for(int i=2;i<=cnte;i+=2)if(!num[i/2]){
int u=to[i],v=to[i^1];
T.update(1,1,cnt_num,num[nex[ps[u]]],num[pre[pt[v]]],dis[u]+ddis[v]+w[i]);
T.update(1,1,cnt_num,num[nex[ps[v]]],num[pre[pt[u]]],dis[v]+ddis[u]+w[i]);
}
read(q);
int u,v;
REP(i,1,q){
read(u),read(v);
int id=mp[u][v];
if(!num[id])printf("%lld\n",dis[tt]);
else{
ll ans=T.query(1,1,cnt_num,num[id]);
if(ans==inf)puts("Infinity");
else printf("%lld\n",ans);
}
}
}
int main(){
File();
init();
work();
return 0;
}