2018 icpc徐州站网络赛 J. Maze Designer 最大生成树LCA

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/82596263

题目

题意:给一个有n*m个点的图,每两个上下或左右的相邻点可以建造墙来使得这两点不能直接连通,造墙的费用题目给出,要求花费最小的费用造墙,使得每两个点都只有一条路径连通,造完墙后,有q个询问,每次询问两个点的路径长度(相邻两点距离为1)。

思路:假设全部建好墙,按照墙的费用从大到小排序,每次删除a到b的墙,就可以理解为加一条无向边a<-->b,是不是只要加n*m-1条费用大的边就可以使得所有点联通,而且可以使得建墙的费用最小呢(删除了n*m-1个费用最大墙),可用kruskal算法实现,接下来根据加入的边用lca模板就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
struct node
{
	int x,y;
	ll cost;
	bool operator<(const node& t)
	{
		return cost>t.cost;
	}
}a[maxn];
int n,m,tot,par[maxn];
vector<int>G[maxn];
void init()
{
	for(int i=1;i<=n*m;i++)
	G[i].clear(),par[i]=i;
	tot=0;
}
void add(int u,int v,int cost)
{
	a[++tot].x=u;
	a[tot].y=v;
	a[tot].cost=cost;
}
int find(int x)
{
	if(par[x]!=x)
	par[x]=find(par[x]);
	return par[x];
}
void kruskal()
{
	sort(a+1,a+1+tot);
	int sum=0;
	for(int i=1;i<=tot;i++)
	{
		int u=find(a[i].x);
		int v=find(a[i].y);
		if(u!=v)
		{
			par[u]=v;
			G[a[i].x].push_back(a[i].y);
			G[a[i].y].push_back(a[i].x);
			sum++;
		}
		if(sum==n*m-1)break;
	}
}
int f[maxn],L[maxn],anc[maxn][20]; 
void dfs(int u,int fa,int deep)//LCA
{
	f[u]=fa;
	L[u]=deep;
	for(int i=0;i<G[u].size();i++)
	if(G[u][i]!=fa)dfs(G[u][i],u,deep+1);
}
void pre()
{
	memset(anc,0,sizeof(anc));
	for(int i=1;i<=n*m;i++)
	{
		anc[i][0]=f[i];
		for(int j=1;(1<<j)<n*m;j++)
		anc[i][j]=-1;
	}
	for(int j=1;(1<<j)<n*m;j++)
	for(int i=1;i<=n*m;i++)
	if(anc[i][j-1]!=-1)
	{
		int t=anc[i][j-1];
		anc[i][j]=anc[t][j-1];
	}
}
int query(int p,int q)
{
	int log,i,ans=0;
	if(L[p]<L[q])swap(p,q);
	for(log=1;(1<<log)<=L[p];log++);log--;
	for(i=log;i>=0;i--)
	if(L[p]-(1<<i)>=L[q])
	{
		ans+=(1<<i);
		p=anc[p][i];
	}
	if(p==q)return ans;
	for(i=log;i>=0;i--)
	if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i])
	{
		ans+=2*(1<<i);
		p=anc[p][i];
		q=anc[q][i];
	}
	ans+=2;
	return ans;
}
int main()
{
	char s1[2],s2[2];
	ll c1,c2;
	while(~scanf("%d%d",&n,&m))
	{
		init();
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			int u=(i-1)*m+j,v1=u+m,v2=u+1;
			scanf("%s%lld%s%lld",s1,&c1,s2,&c2);
			if(s1[0]=='D')add(u,v1,c1);
			if(s2[0]=='R')add(u,v2,c2);
		}
		kruskal();
		dfs(1,-1,0);
		pre();
		int q,x1,x2,y1,y2;
		scanf("%d",&q);
		while(q--)
		{
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			int u=(x1-1)*m+y1;
			int v=(x2-1)*m+y2;
			printf("%d\n",query(u,v));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/82596263