码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2125 最短路 静态仙人掌

时间:2015-02-18 16:30:02      阅读:299      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2125   tarjan   倍增lca   

题目大意:给定一棵仙人掌,多次询问两点之间的最短路

静态仙人掌= = 在VFK讲仙人掌之前就想做= = 结果一直拖= =

好不容易写完了= = 刚过样例 BZ就开始维护- - 维护到闭营= = 交上去还WA了= = 尼玛我这傻逼到底还是把倍增LCA写挂了= =

算了回归正题


首先我们的思路是这样的

考虑给定的是一棵树 多次询问树上两点间距离 

那么我们一般的做法是预处理每个点到根的距离 用两点到根距离之和减掉LCA到根距离的2倍

那么到了仙人掌上我们也可以套用这个做法


首先Tarjan处理出每个环 处理出环上每个点到根节点的最短路

但是有一个问题 如果LCA在环上的话环上的最短距离可能是这个环被分成的两段中的任意一段

因此我们另建一棵树

在这棵树上 对于每个环我们定义深度最小的点为这个环的根

每个环变成一个节点连向环的根 环上其他节点连向这个环

因此如果两个点的LCA是环 就会出现这种情况 在两端之中选择短的一条即可


具体实现啥的= = 各种STL啥的真是对不起了= = 反正这种数据范围怎么可能卡常嘛啊哈哈哈= =

#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 10100
#define INF 0x3f3f3f3f
using namespace std;

int n,m,q,cnt;

map<int,int> f[M];
vector<int> belong[M];
int dis[M];

vector<int> rings[M];
int size[M];
map<int,int> dist[M];

void Add(int x,int y,int z)
{
	if( f[x].find(y)==f[x].end() )
		f[x][y]=INF;
	f[x][y]=min(f[x][y],z);
}
namespace Cactus_Graph{
	int fa[M<<1][16],dpt[M<<1];
	pair<int,int> second_lca;
	int Get_Depth(int x)
	{
		if(!fa[x][0]) dpt[x]=1;
		if(dpt[x]) return dpt[x];
		return dpt[x]=Get_Depth(fa[x][0])+1;
	}
	void Pretreatment()
	{
		int i,j;
		for(j=1;j<=15;j++)
		{
			for(i=1;i<=cnt;i++)
				fa[i][j]=fa[fa[i][j-1]][j-1];
			for(i=n+1;i<=n<<1;i++)
				fa[i][j]=fa[fa[i][j-1]][j-1];
		}
		for(i=1;i<=cnt;i++)
			Get_Depth(i);
		for(i=n+1;i<=n<<1;i++)
			Get_Depth(i);
	}
	int LCA(int x,int y)
	{
		int j;
		if(dpt[x]<dpt[y])
			swap(x,y);
		for(j=15;~j;j--)
			if(dpt[fa[x][j]]>=dpt[y])
				x=fa[x][j];
		if(x==y) return x;
		for(j=15;~j;j--)
			if(fa[x][j]!=fa[y][j])
				x=fa[x][j],y=fa[y][j];
		second_lca=make_pair(x,y);
		return fa[x][0];
	}
}
void Tarjan(int x)
{
	static int dpt[M],low[M],T;
	static int stack[M],top;
	map<int,int>::iterator it;
	dpt[x]=low[x]=++T;
	stack[++top]=x;
	for(it=f[x].begin();it!=f[x].end();it++)
	{
		if(dpt[it->first])
			low[x]=min(low[x],dpt[it->first]);
		else
		{
			Tarjan(it->first);
			if(low[it->first]==dpt[x])
			{
				int t;
				rings[++cnt].push_back(x);
				belong[x].push_back(cnt);
				Cactus_Graph::fa[cnt][0]=n+x;
				do{
					t=stack[top--];
					rings[cnt].push_back(t);
					Cactus_Graph::fa[n+t][0]=cnt;
				}while(t!=it->first);
			}
			low[x]=min(low[x],low[it->first]);
		}
	}
}
void DFS(int x)
{
	vector<int>::iterator it,_it;

	static int stack[M];int i,j,top=0;
	for(it=rings[x].begin();it!=rings[x].end();it++)
		stack[++top]=*it;
	stack[++top]=*rings[x].begin();

	for(i=1;i<top;i++)
	{
		int p1=stack[i],p2=stack[i+1];
		size[x]+=f[p1][p2];
		if(i!=top-1)
			dist[x][p2]=dist[x][p1]+f[p1][p2];
	}

	i=2;j=top-1;
	while(i<=j)
	{
		if(dis[stack[i-1]]+f[stack[i-1]][stack[i]]<dis[stack[j+1]]+f[stack[j+1]][stack[j]])
			dis[stack[i]]=dis[stack[i-1]]+f[stack[i-1]][stack[i]],i++;
		else
			dis[stack[j]]=dis[stack[j+1]]+f[stack[j+1]][stack[j]],j--;
	}

	for(_it=rings[x].begin(),_it++;_it!=rings[x].end();_it++)
		for(it=belong[*_it].begin();it!=belong[*_it].end();it++)
			DFS(*it);
}
int main()
{
	using namespace Cactus_Graph;
	int i,x,y,z;
	cin>>n>>m>>q;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		Add(x,y,z);Add(y,x,z);
	}
	Tarjan(1);
	Pretreatment();
	vector<int>::iterator it;
	for(it=belong[1].begin();it!=belong[1].end();it++)
		DFS(*it);
	for(i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		int lca=LCA(n+x,n+y);
		if(lca>n) printf("%d\n",dis[x]+dis[y]-2*dis[lca-n]);
		else
		{
			int ans=dis[x]+dis[y]-dis[second_lca.first-n]-dis[second_lca.second-n];
			int temp=abs(dist[lca][second_lca.first-n]-dist[lca][second_lca.second-n]);
			ans+=min(temp,size[lca]-temp);
			printf("%d\n",ans);
		}
	}
	return 0;
}


BZOJ 2125 最短路 静态仙人掌

标签:bzoj   bzoj2125   tarjan   倍增lca   

原文地址:http://blog.csdn.net/popoqqq/article/details/43876907

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!