BZOJ2725: [Violet 6]故乡的梦【线段树+最短路】

2725: [Violet 6]故乡的梦

【题目描述】

传送门

【题解】

我们会发现,如果我们要走x-y这条边,一定会走一段最短路到x1(这里的最短路表示(S,T)的最短路),然后走一段非最短路到x,从y走一段非最短路到最短路上的点y1,然后走一段最短路到T。所以这条边影响的最短路为x1到y1这一段,所以我们之间线段树维护这个区间最小值。

【代码如下】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=200005;
typedef long long LL;
int n,m,cnt,Q,S[2],Fa[2][MAXN],P[MAXN];LL Dst[2][MAXN],INF,Add[MAXN<<2],Ans[MAXN];bool vis[MAXN];
struct Edge{
	int tot,lnk[MAXN],son[MAXN<<1],nxt[MAXN<<1],W[MAXN<<1];
	void Add(int x,int y,int w){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;W[tot]=w;}
}E;
struct HEAP{
	LL x;int id,fa;
	bool operator <(const HEAP b)const{return x>b.x;}
}Hep[MAXN];int Len;
void put(LL x,int id,int fa){Hep[++Len]=(HEAP){x,id,fa};push_heap(Hep+1,Hep+1+Len);}
HEAP get(){pop_heap(Hep+1,Hep+1+Len);return Hep[Len--];}
void Dij(bool f,int a){
	memset(Dst[a],63,sizeof(Dst[a]));memset(Fa[a],0,sizeof(Fa[a]));memset(vis,0,sizeof(vis));
	Len=0;put(Dst[a][S[a]]=0,S[a],0);
	while(Len){
		HEAP Now=get();int x=Now.id,fa=Now.fa;
		if(vis[x]) continue;vis[x]=1;
		if(f) Fa[a][x]=fa;else Fa[a][x]=P[x]?x:Fa[a][fa];
		for(int j=E.lnk[x];j;j=E.nxt[j]) if(Dst[a][E.son[j]]>Dst[a][x]+E.W[j]) put(Dst[a][E.son[j]]=Dst[a][x]+E.W[j],E.son[j],x);
	}
}
void PushDown(int rt,int L,int R){
	if(L==R){Ans[L]=Add[rt];return;}int mid=(R+L)>>1;
	Add[rt<<1]=min(Add[rt],Add[rt<<1]);Add[rt<<1|1]=min(Add[rt],Add[rt<<1|1]);Add[rt]=INF;
	PushDown(rt<<1,L,mid);PushDown(rt<<1|1,mid+1,R);
}
void Insert(int rt,int L,int R,int l,int r,LL p){
	if(l<=L&&R<=r){Add[rt]=min(Add[rt],p);return;}
	int mid=(R+L)>>1;
	if(l<=mid) Insert(rt<<1,L,mid,l,r,p);
	if(r>mid) Insert(rt<<1|1,mid+1,R,l,r,p);
}
#include<cctype>
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
	return f?ret:-ret;
}
int main(){
	n=read(),m=read();memset(Add,63,sizeof(Add));INF=Add[0];
	for(int i=1,x,y,w;i<=m;i++) x=read(),y=read(),w=read(),E.Add(x,y,w),E.Add(y,x,w);
	S[0]=read(),S[1]=read();Dij(1,1);
	for(int i=S[0];i!=S[1];i=Fa[1][i]) P[i]=++cnt;P[S[1]]=++cnt;
	Dij(0,0),Dij(0,1);
	for(int i=1;i<=n;i++)
	for(int j=E.lnk[i];j;j=E.nxt[j]){
		if(P[i]&&P[E.son[j]]&&P[i]<P[E.son[j]]&&(P[E.son[j]]-P[i]<=1)) continue; 
		int x=Fa[0][i],y=Fa[1][E.son[j]];
		if(x&&y&&P[y]-P[x]>0) Insert(1,1,cnt,P[x],P[y]-1,Dst[0][i]+Dst[1][E.son[j]]+E.W[j]);
	}
	PushDown(1,1,cnt);Q=read();
	for(int i=1,x,y;i<=Q;i++){
		x=read(),y=read();
		if(P[x]>P[y]) swap(x,y);
		if(!P[x]||!P[y]||P[y]-P[x]>1) printf("%lld\n",Dst[0][S[1]]);
		else printf(Ans[P[x]]==INF?"Infinity\n":"%lld\n",Ans[P[x]]);
	}
	return 0;
}
posted @ 2019-03-06 18:02  XSamsara  阅读(349)  评论(0编辑  收藏  举报