Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个 n ∗ n n*n nn 的矩阵,有些位置存在障碍物,现在有 q q q 次询问,每次询问给出两个点 s t = ( x 1 , y 1 ) , e d = ( x 2 , y 2 ) st=(x1,y1),ed=(x2,y2) st=(x1,y1),ed=(x2,y2),需要回答从 s t st st 开始推箱子,可以推到 e d ed ed 的最大箱子的边长是多少

题目分析:首先不难想到预处理出以每个点为中心时,可以放置箱子的最大边长,可以通过二维前缀和+二分的思路在 O ( n 2 l o g n ) O(n^2logn) O(n2logn) 的复杂度内求解,不过代码不是很好写。考虑到本题规定了正方形的边长一定是奇数,在纸上画画不难发现,当正方形确定后,如果每次可以扩展八个方向,那么正方形的四个边界以及对角到中心的距离都是相等的,依据这个可以用 f l o o d − f i l l flood-fill floodfill 算法在 O ( n 2 ) O(n^2) O(n2) 的时间复杂度内实现,且代码相对简单,注意不要忘记考虑边界带来的影响。

现在问题转换为了,需要找到一条 s t st st e d ed ed 的路径,满足路径上的最小值最大。这不就是最小瓶颈树的模板题吗?因为本题是令最小值最大,所以对原图构造一个最大生成树即可,那么后续的每次询问,都转换成了:在最大生成树上, s t st st e d ed ed 这条路径上边权的最小值是多少。

为了避免在树上边权转点权的细节操作,不如直接对上述操作构建一下克鲁斯卡尔重构树,这样一来每次询问就变成了询问两点的 L C A LCA LCA 的权值了

代码:

// Problem: Hangar Hurdles
// Contest: Virtual Judge - Gym
// URL: https://vjudge.net/problem/Gym-101173H
// Memory Limit: 524 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=2e6+100;
const int b[8][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
char maze[1010][1010];
int id[1010][1010],d[1010][1010],tot;
struct Ex_Kruskal
{
	struct Edge
	{
		int x,y,w;
		bool operator<(const Edge& t)const
		{
			return w>t.w;
		}
	}edge[N];
	int f[N],val[N],dp[N][25],deep[N],index,cnt,n;
	vector<int>node[N];
	void init(int n)
	{
		cnt=tot=0;
		index=n;
		for(int i=0;i<=n<<1;i++)
		{
			f[i]=i;
			node[i].clear();
		}
	}
	int find(int x)
	{
		return f[x]==x?x:f[x]=find(f[x]);
	}
	void addedge(int x,int y,int w)
	{
		edge[++cnt]={x,y,w};
	}
	void solve()
	{
		sort(edge+1,edge+1+cnt);
		for(int i=1;i<=cnt;i++)
		{
			int xx=find(edge[i].x),yy=find(edge[i].y);
			if(xx!=yy)
			{
				f[xx]=f[yy]=++index;
				node[index].push_back(xx);
				node[index].push_back(yy);
				val[index]=edge[i].w;
			}
		}
		n=index;
		for(int i=1;i<=n;i++)
			if(find(i)==i)
				dfs(i,0,0);
	}
	void dfs(int u,int fa,int dep)
	{
		deep[u]=dep;
		dp[u][0]=fa;
		for(int i=1;i<=20;i++) {
			dp[u][i]=dp[dp[u][i-1]][i-1];
		}
		for(auto v:node[u])
			dfs(v,u,dep+1);
	}
	int LCA(int a,int b)
	{
		if(deep[a]<deep[b])
			swap(a,b);
		for(int i=20;i>=0;i--)
			if(deep[a]-deep[b]>=(1<<i))
				a=dp[a][i];
		if(a==b)
			return a;
		for(int i=20;i>=0;i--)
			if(dp[a][i]!=dp[b][i])
			{
				a=dp[a][i];
				b=dp[b][i];
			}
		return dp[a][0];
	}
	int cal(int x,int y) {
		return val[LCA(x,y)];
	}
}T;
void bfs(int n) {
	memset(d,-1,sizeof(d));
	queue<pair<int,int>>q;
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			if(maze[i][j]=='#') {
				q.push({i,j});
				d[i][j]=0;
			}
		}
	}
	for(int i=1;i<=n;i++) {
		d[0][i]=d[i][0]=d[n+1][i]=d[i][n+1]=0;
		q.push({0,i});
		q.push({i,0});
		q.push({n+1,i});
		q.push({i,n+1});
	}
	while(q.size()) {
		int x,y;
		tie(x,y)=q.front();
		q.pop();
		for(int i=0;i<8;i++) {
			int xx=x+b[i][0],yy=y+b[i][1];
			if(xx<=0||xx>n||yy<=0||yy>n) {
				continue;
			}
			if(d[xx][yy]!=-1) {
				continue;
			}
			d[xx][yy]=d[x][y]+1;
			q.push({xx,yy});
		}
	}
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			if(d[i][j]) {
				d[i][j]=d[i][j]*2-1;
			}
		}
	}
}
void build(int n) {
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			if(i+1<=n) {
				T.addedge(id[i][j],id[i+1][j],min(d[i][j],d[i+1][j]));
			}
			if(j+1<=n) {
				T.addedge(id[i][j],id[i][j+1],min(d[i][j],d[i][j+1]));
			}
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n;
	read(n);
	for(int i=1;i<=n;i++) {
		scanf("%s",maze[i]+1);
		for(int j=1;j<=n;j++) {
			id[i][j]=++tot;
		}
	}
	T.init(n*n);
	bfs(n);
	build(n);
	T.solve();
	int q;
	read(q);
	while(q--) {
		int x1,y1,x2,y2;
		read(x1),read(y1),read(x2),read(y2);
		printf("%d\\n",T.cal(id[x1][y1],id以上是关于Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)的主要内容,如果未能解决你的问题,请参考以下文章

[转帖](整理)GNU Hurd项目详解

[CERC2016]Hangar Hurdles

Oracle加码自主云服务,透露区块链计划

Gym101522A Gym101522C Gym101522D

Gym Gym 101147G 第二类斯特林数

OpenAI Gym 入门与提高 Gym环境构建与最简单的RL agent