1. 程式人生 > >[bzoj2725]故鄉的夢——最短路+線段樹 dalaos' blogs Some Links

[bzoj2725]故鄉的夢——最短路+線段樹 dalaos' blogs Some Links

題目大意:

給定一個帶權無向圖,每次詢問刪除一條邊之後從S到T的最短路是多少?(各個詢問之間獨立)

思路:

如果刪除的邊不在最短路中或者可以被替換,那麼答案即為最短路。
如果刪除的邊在最短路中並且不可以被替換,考慮將這條邊刪除的新圖:
假設原來的最短路為 S > T S->T

,那麼新的最短路一定是 S > u > x >
y > v > T S->u->x->y->v->T
(其中u,v在原來的最短路上,x,y不在原來的最短路上)
於是我們發現如果刪除了這條邊之後S和T聯通,那麼一定會經過形如 x > y x->y 這樣的路徑,即經過原本不在最短路中的邊。
並且對於 x > y x->y 中的一條邊(uu,vv), S > u u S->uu v v > T vv->T 一定是兩條最短的路徑於是我們枚舉出每一條不在最短路中的邊(uu,vv),並計算出對應的最早的u和最晚的v,用強制經過(uu,vv)的最短路去更新u和v中間缺失的那些邊的答案。為了方便,在具體實現的時候隨意提出一條 S > T 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;
}