Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)相关的知识,希望对你有一定的参考价值。
题目链接:点击查看
题目大意:给出一个 n ∗ n n*n n∗n 的矩阵,有些位置存在障碍物,现在有 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 flood−fill 算法在 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+克鲁斯卡尔重构树)的主要内容,如果未能解决你的问题,请参考以下文章