BZOJ 2125 最短路

题解:建立圆方树,每个点向环内深度最浅的点连边

分LCA是不是方点讨论即可

如果是方点讨论从哪边绕过去的

园点的话直接用最短路处理即可

问题:双联通分量不熟

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int maxn=100009;
const int inf=1000000000;

int n,m,T;
map<int,int>ma[maxn];

struct Edge{
	int from,to,dist;
};
vector<int>G[maxn];
vector<Edge>edges;
void Addedge(int x,int y,int z){
	Edge e;
	e.from=x;e.to=y;e.dist=z;
	edges.push_back(e);
	G[x].push_back(edges.size()-1);
}

queue<int>q;
int inq[maxn];
int d[maxn];
void Spfa(){
	for(int i=1;i<=n;++i){
		d[i]=inf;inq[i]=0;
	}
	d[1]=0;inq[1]=1;q.push(1);
	while(!q.empty()){
		int x=q.front();q.pop();inq[x]=0;
		for(int i=0;i<G[x].size();++i){
			Edge e=edges[G[x][i]];
			if(d[x]+e.dist<d[e.to]){
				d[e.to]=d[x]+e.dist;
				if(!inq[e.to]){
					q.push(e.to);
					inq[e.to]=1;
				}
			}
		}
	}
}

int dfsclock,scccnt;
int pre[maxn],lowlink[maxn],ref[maxn];
int lastpoint[maxn],restedge[maxn];
int S[maxn],top;
int dt[maxn];
int vis[maxn];
int depth[maxn];
int father[maxn];
vector<int>son[maxn];
void Dfs(int u,int fa){
//	printf("now in point %d\n",u);
//	for(int i=1;i<=5e8;++i);
	pre[u]=lowlink[u]=++dfsclock;
	ref[dfsclock]=u;
	S[++top]=u;
//	cout<<u<<' '<<S.size()<<endl;
	
	for(int i=0;i<G[u].size();++i){
		Edge e=edges[G[u][i]];
//		if(edges[G[u][i]^1].from==fa)continue;
		int v=e.to;
		if(v==fa)continue;
		if(!pre[v]){
			dt[v]=dt[u]+e.dist;
			Dfs(v,u);
			lowlink[u]=min(lowlink[u],lowlink[v]);
		}else if(!vis[v]){
//			cout<<u<<' '<<v<<endl;
			lowlink[u]=min(lowlink[u],pre[v]);
			restedge[u]=e.dist;
			for(int i=top;S[i]!=v;--i){
				int x=S[i];
//				cout<<x<<' '<<v<<endl;
				if(x==v)break;
				father[x]=v;
				lastpoint[x]=u;
				son[v].push_back(x);
//				printf("push(%d)\n",x);
//				if(S.size()==0)cout<<u<<endl;
			}
		}
	}
//	cout<<u<<" AFSD "<<S.size()<<endl;
	if(lowlink[u]==pre[u]){
		father[u]=fa;
		son[fa].push_back(u);
//		printf("push(%d)\n",u);
	}
	--top;
	vis[u]=1;
//	printf("now out point %d\n",u);
}

void Getdepth(int now,int fa){
	depth[now]=depth[fa]+1;
	for(int i=0;i<son[now].size();++i){
		if(son[now][i]==fa)continue;
		Getdepth(son[now][i],now);
	}
}

int f[maxn][20];
void LCAinit(){
	for(int i=1;i<=n;++i)f[i][0]=father[i];
	for(int j=1;j<=19;++j){
		for(int i=1;i<=n;++i){
			f[i][j]=f[f[i][j-1]][j-1];
		}
	}
}
int Getlca(int x,int y){
	if(depth[x]<depth[y])swap(x,y);
	for(int j=19;j>=0;--j){
		if(depth[f[x][j]]>=depth[y])x=f[x][j];
	}
	if(x==y)return x;
	for(int j=19;j>=0;--j){
		if(f[x][j]!=f[y][j]){
			x=f[x][j];y=f[y][j];
		}
	}
	return f[x][0];
}
int Getpoint(int x,int y){
	for(int j=19;j>=0;--j){
		if(depth[f[x][j]]>depth[y])x=f[x][j];
	}
	return x;
}

int Getans(int x,int y){
	if(depth[x]<depth[y])swap(x,y);
	int lca=Getlca(x,y);
//	cout<<"lca="<<lca<<endl;
	if(lca==y){
//		if(d[x]-d[y]==6760174)cout<<"AD"<<endl;
		return d[x]-d[y];
	}
	
	int px=Getpoint(x,lca);
	int py=Getpoint(y,lca);
	
	if((lastpoint[px]!=lastpoint[py])||(lastpoint[px]==0)||(lastpoint[py]==0)){
		return d[x]+d[y]-2*d[lca];
	}else{
		int ans=d[x]+d[y]-d[px]-d[py];
		int tmp;
		if(dt[px]>dt[py])tmp=dt[px]-dt[py];
		else tmp=dt[py]-dt[px];
//		printf("%d %d\n",lastpoint[px],restedge[lastpoint[px]]);
		int ans1=ans+tmp;
		int ans2=ans+restedge[lastpoint[px]]+dt[lastpoint[px]]-dt[ref[lowlink[px]]]-tmp;//6760174
		if(ans2==6760174){
			printf("tmp=%d lastpoint=%d ref[]=%d\n",tmp,lastpoint[py],ref[lowlink[px]]);
		}
		return min(ans1,ans2);
	}
}

int main(){
//	freopen("cactus.in","r",stdin);
//	freopen("cactus.out","w",stdout);
//	
	scanf("%d%d%d",&n,&m,&T);
	while(m--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		if(ma[x].count(y)){
			ma[x][y]=min(ma[x][y],z);
		}else if(ma[y].count(x)){
			ma[y][x]=min(ma[y][x],z);
		}else{
			ma[x][y]=z;
		}
	}
	for(int i=1;i<=n;++i){
		for(map<int,int>::iterator it=ma[i].begin();it!=ma[i].end();++it){
			Addedge(i,it->first,it->second);
			Addedge(it->first,i,it->second);
		}
	}
	
	Spfa();
	Dfs(1,0);
	Getdepth(1,0);
	LCAinit();
	
//	for(int i=1;i<=n;++i)cout<<depth[i]<<' ';
//	cout<<endl;
	while(T--){
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",Getans(x,y));
	}
	
	return 0;
}

  

posted @ 2018-02-21 11:16  ws_zzy  阅读(163)  评论(0编辑  收藏  举报