[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;
}

posted @ 2018-10-27 14:27  ylsoi  阅读(276)  评论(0编辑  收藏  举报