BZOJ2125: 最短路

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2125: 最短路相关的知识,希望对你有一定的参考价值。

传送门

圆方树练习。

首先搞出圆方树(建树)。注意在建树的过程中即Tarjan时要同时记录三个信息:1.环的大小。 2.环上每个点到环顶点的距离。 3.最优距离在那一边。

这些都很容易求出来。然后我们把圆点到方点的边权赋为环到顶点的最短距离,方点到圆点的赋为0。

对于每次询问的两个点,询问在圆方树上的LCA,如果LCA是圆点,直接计算即可。下面分析方点的情况。

如果两点的LCA是方点,那么显然在原仙人掌的环上。

这时候对于这个可以选择两条路径,根据题目显然不能暴力走。

对于仙人掌上的两个点,因为我们已经求出最优距离应该走哪一边,而且我们知道了环的大小,所以相对来时没那么优的一条路径也可以计算出来。

所以如果两个点的最优选择是不同方向的,直接用环的大小减去即可。如果是相同方向的,分别计算,取MIN即可。

//BZOJ2125
//by Cydiater
//2017.2.13
#include <iostream>
#include <queue>
#include <map>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <bitset>
#include <set>
#include <vector>
#include <complex>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define Auto(i,node)	for(int i=LINK[node];i;i=e[i].next)
const int MAXN=1e5+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,M,Q,NN,Girth[MAXN];
vector<int>E[MAXN],W[MAXN];
bool cho[MAXN];
struct Info{
	int sx,sy,lca;
};
struct Graph{
	int LINK[MAXN],len,dfn[MAXN],low[MAXN],stack[MAXN],top,dfs_clock,dep[MAXN],fa[MAXN][25],dis[MAXN][25];
	struct edge{
		int y,next,v;
	}e[MAXN];
	inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
	inline void Insert(int x,int y,int v){insert(x,y,v);insert(y,x,v);}
	int Col(int id){
		int dist=0,siz=E[id].size();
		up(i,0,siz-1){
			int x=E[id][i],y=E[id][(i+1)%siz];
			Auto(j,x)if(e[j].y==y){
				dist+=e[j].v;
				W[id].push_back(e[j].v);
			}
		}
		return dist;
	}
	void Tarjan(int node){
		dfn[node]=low[node]=++dfs_clock;
		stack[++top]=node;
		Auto(i,node)if(!dfn[e[i].y]){
			Tarjan(e[i].y);
			cmin(low[node],low[e[i].y]);
			if(low[e[i].y]>=dfn[node]){
				NN++;int tmp;
				do{
					tmp=stack[top--];
					E[NN].push_back(tmp);
				}while(tmp!=e[i].y);
				E[NN].push_back(node);
				Girth[NN]=Col(NN);
			}
		}else cmin(low[node],dfn[e[i].y]);
	}
	void DFS(int node,int father,int deep){
		fa[node][0]=father;dep[node]=deep;
		Auto(i,node)if(e[i].y!=father)
			DFS(e[i].y,node,deep+1);
		if(node>N){
			dis[node][0]=0;
			int siz=E[node].size(),dist=0;
			down(j,siz-2,0){
				dist+=W[node][j];
				dis[E[node][j]][0]=min(dist,Girth[node]-dist);
				if(dis[E[node][j]][0]==dist)	cho[E[node][j]]=0;
				else 				cho[E[node][j]]=1;
			}
		}
	}
	void Get_Ancestor(){
		up(i,1,20)up(node,1,N)if(fa[node][i-1]){
			fa[node][i]=fa[fa[node][i-1]][i-1];
			dis[node][i]=dis[node][i-1]+dis[fa[node][i-1]][i-1];
		}
	}
	Info LCA(int x,int y){
		if(x==y)	return (Info){0,0,x};
		if(dep[x]<dep[y])swap(x,y);
		down(i,20,0)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i];
		if(x==y)	return (Info){0,0,x};
		down(i,20,0)if(fa[x][i]!=0&&fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
		return (Info){x,y,fa[x][0]};
	}
	int Get(int node,int aim){
		int ans=0;
		down(i,20,0)if(dep[node]-(1<<i)>=dep[aim]){
			ans+=dis[node][i];
			node=fa[node][i];
		}
		return ans;
	}
}G1,G2;
namespace solution{
	void Prepare(){
		N=read();M=read();Q=read();
		while(M--){
			int x=read(),y=read(),v=read();
			G1.Insert(x,y,v);
		}
		NN=N;
		G1.Tarjan(1);
		up(i,N+1,NN){
			int siz=E[i].size();
			up(j,0,siz-1)G2.Insert(i,E[i][j],0);
		}
		G2.DFS(1,0,0);
		G2.Get_Ancestor();
		//up(i,1,N)cout<<G2.dis[i][0]<<endl;
	}
	void Solve(){
		while(Q--){
			int x=read(),y=read(),ans=0;
			Info info=G2.LCA(x,y);
			int lca=info.lca,sx=info.sx,sy=info.sy;
			if(lca>N){
				int tmp;
				if(cho[sx]^cho[sy])	tmp=G2.dis[sx][0]+G2.dis[sy][0];
				else			tmp=min(Girth[lca]-G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-G2.dis[sy][0]+G2.dis[sx][0]);
				ans=G2.Get(x,sx)+G2.Get(y,sy)+min(G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-tmp);
			}
			else		ans=G2.Get(x,lca)+G2.Get(y,lca);
			printf("%d\n",ans);
		}
	}
}
int main(){
	using namespace solution;
	Prepare();
	Solve();
	return 0;
}

 

以上是关于BZOJ2125: 最短路的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2125 最短路——仙人掌两点间最短路

BZOJ 2125 最短路

BZOJ 2125 最短路

[bzoj2125]最短路

题解Bzoj2125最短路

bzoj2125 最短路