bzoj2725 故乡的梦
题目描述
https://www.lydsy.com/JudgeOnline/problem.php?id=2725
题解
给你一张图,每次删除一条边问当前的最短路。
先随便拉一条最短路出来,如果删除的边不在这条最短路上那么答案就是原图最短路。
如果删除的边在最短路上,那么新的最短路肯定是从s开始先在最短路上跑一段,在外面跑一段再回到最短路上。
对于每条不在最短路上的边,我们找到它对应的最短路链上对于S和对于T的最近点,len=ws[i]+wt[i]+edge,两个最近点分别为L,R。
如果删除的边在[L,R]内,那么这组最短路就可行。所以我们建一棵线段树,对于每条边求出[L,R]并把这个区间赋个最小值,查询的时候在线段树上对应查询就好了。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 9999999999999999ll
#define N 200010
using namespace std;
int n,m,Q,ss,tt,k=1,cnt,pre[N],la[N],ff[N*2];
int g[2][N],tag[N],po[N],d[N];ll w[2][N];
struct node{int a,b,c;}e[N*2];
struct info{
int x;ll y;
bool operator<(const info &p)const{return y>p.y;}
};
struct data{ll minn;}t[N*4];
priority_queue<info>q;
map<int,int>h[N];
void add(int a,int b,int c)
{
e[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;
e[++k]=(node){b,a,c};ff[k]=la[b];la[b]=k;
h[a][b]=h[b][a]=(k>>1);
}
int find(int x,int p)
{
if(!x)return 0;
if(g[p][x])return g[p][x];
return g[p][x]=find(e[pre[x]].a,p);
}
void dij(int S,int p)
{
for(int i=1;i<=n;i++)w[p][i]=inf;
q.push((info){S,w[p][S]=0});pre[S]=0;
while(q.size())
{
info tmp=q.top();q.pop();
int x=tmp.x;ll y=tmp.y;
if(w[p][x]!=y)continue;
for(int a=la[x];a;a=ff[a])
if(w[p][e[a].b]>y+e[a].c)
{
pre[e[a].b]=a;w[p][e[a].b]=y+e[a].c;
q.push((info){e[a].b,w[p][e[a].b]});
}
}
if(!p)
{
int pos=tt;
while(pos)
{
tag[pre[pos]>>1]=1;g[p][pos]=pos;cnt++;
d[po[cnt]=pos]=cnt;pos=e[pre[pos]].a;
}
}
else for(int i=1;i<=cnt;i++)g[p][po[i]]=po[i];
for(int i=1;i<=n;i++)g[p][i]=find(i,p);
}
class seg_tree
{
public:
void build(int x,int l,int r)
{
t[x].minn=inf;if(l==r)return;
int mid=l+r>>1,lc=x<<1,rc=lc+1;
build(lc,l,mid);build(rc,mid+1,r);
}
void modify(int x,int l,int r,int ql,int qr,ll val)
{
if(ql<=l&&r<=qr){
t[x].minn=min(t[x].minn,val);return;
}
int mid=l+r>>1,lc=x<<1,rc=lc+1;
if(ql<=mid)modify(lc,l,mid,ql,qr,val);
if(qr>mid)modify(rc,mid+1,r,ql,qr,val);
}
ll qry(int x,int l,int r,int pos)
{
if(l==r)return t[x].minn;
int mid=l+r>>1,lc=x<<1,rc=lc+1;
ll res=t[x].minn;
if(pos<=mid)res=min(res,qry(lc,l,mid,pos));
else res=min(res,qry(rc,mid+1,r,pos));
return res;
}
}T;
int main()
{
//freopen("1.in","r",stdin);
int a,b,c,L,R;ll len,ans;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&a,&b,&c),add(a,b,c);
scanf("%d%d",&ss,&tt);
dij(ss,0);dij(tt,1);T.build(1,1,cnt);
for(int i=2;i<=k;i++)
{
if(tag[i>>1])continue;
L=d[g[0][e[i].a]];R=d[g[1][e[i].b]];
len=w[0][e[i].a]+w[1][e[i].b]+e[i].c;
if(L>R)swap(L,R);
if(L&&R&&L<R)T.modify(1,1,cnt,L,R-1,len);
}
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&a,&b);
if(!tag[h[a][b]])ans=w[0][tt];
else ans=T.qry(1,1,cnt,min(d[a],d[b]));
if(ans==inf)printf("Infinity\n");
else printf("%lld\n",ans);
}
return 0;
}