【bzoj4242 水壶】

Description

JOI君所居住的IOI市以一年四季都十分炎热著称。

IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有P个,编号为1...P。

JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。

JOI君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此IOI市的市民一般都携带水壶出行。大小为x的水壶最多可以装x单位的水,建筑物里有自来水可以将水壶装满。

由于携带大水壶是一件很困难的事情,因此JOI君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。

现在给出IOI市的地图和Q个询问,第i个询问(1<=i<=Q)为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。

Input

第一行四个空格分隔的整数H,W,P,Q,表示IOI市被分成了纵H*横W块区域,有P个建筑物,Q次询问。

接下来H行,第i行(1<=i<=H)有一个长度为W的字符串,每个字符都是’.’或’#’之一,’.’表示这个位置是建筑物或原野,’#’表示这个位置是墙壁。

接下来P行描述IOI市每个建筑物的位置,第i行(1<=i<=P)有两个空格分隔的整数Ai和Bi,表示第i个建筑物的位置在第Ai行第Bi列。保证这个位置在地图中是’.’

接下来Q行,第i行(1<=i<=Q)有两个空格分隔的整数Si和Ti,表示第i个询问为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”

Output

输出Q行,第i行(1<=i<=Q)一个整数,表示在建筑物Si和Ti之间移动最小需要多大的水壶。

如果无法到达,输出-1。此外,如果不需要经过原野就能到达,输出0。

好题。不过我太菜了做了好几个小时。

题目大意就是给你一个2000*2000的图形,在这个图形里有一些障碍,还有200000个点。

每次给你一对点,让你求这对点之间的点与点的路径中最小的最大值。

首先找两个点之间路径上边的最小的最大值,那么直接想到货车运输这道题,但是我们有的不是一颗树而是一个图。所以需要我们建边。

个人认为这个题最大的难点就在建边。

因为点数是200000级别的,先不管建完图跑什么算法,光是建边就建不了。

那么我们想一下,题目中给了一个很奇怪的图,所以我们从这个图入手。

很容易想到,不可能建出\(n^2\)条边,我们只能找一些点满足这两个点没有其他的点,再把这两个点连起来。所以现在来思博一下:我们把在这个图上的每个点看成一个小岛,并且每个小岛还能不断扩大,那么当小岛扩大到相邻时,我们就可以把这两个小岛代表的点连起来,这样的连边策略一定是最优的。

以为首先,我们保证了每个点之间都可以互相到达,其次我们要求的是最大边最小,所以尽可能的让边短一点,那就肯定是找最近的,小岛策略正好符合。

所以我们建边的方式就是BFS,将每一个点扔到队列里,再以每个点为中心向四个方向扩散,如果扩散到的点没有被标记,那么就打上标记化作这个点的领地。相反,如果扩散到的点被标记,那么我们认为这两个小岛相连了,那么就直接连一条边就行。

有考虑到会有障碍,所以在BFS的时候记一个步数就行。

建完边之后问题就变得可做了很多。

我们先跑一遍MST,然后直接倍增LCA就可以了。

细节比较多,好题。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int wx=2017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int num,tot;
int n,m,qq,p;
char c[200017];
queue<int > q;
int dx[]={0,1,0,-1,0};
int dy[]={0,0,1,0,-1};
int a[wx][wx],vis[wx][wx],dis[wx][wx];
int d[200017][21],f[200017][21],fa[200017];
int dep[4000017];
int head[4000017r];
struct node{
int l,r,d;
friend bool operator < (const node& a,const node& b){
return a.d<b.d;
}
}t[4000017];
struct e{
int nxt,to,dis;
}edge[4000017];
void add(int from,int to,int dis){
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void bfs(){
while(q.size()){
int ux=q.front();q.pop();
int uy=q.front();q.pop();
for(int i=1;i<=4;i++){
int ex=ux+dx[i];
int ey=uy+dy[i];
if(ex<1||ex>n||ey<1||ey>m||a[ex][ey])continue;
if(dis[ex][ey]==-1){
vis[ex][ey]=vis[ux][uy];dis[ex][ey]=dis[ux][uy]+1;
q.push(ex);q.push(ey);
}
else {
if(vis[ex][ey]!=vis[ux][uy]){
t[++tot].l=vis[ux][uy];
t[tot].r=vis[ex][ey];
t[tot].d=dis[ex][ey]+dis[ux][uy];
}
}
}
}
}
void Kruskal(){
for(int i=1;i<=p;i++)fa[i]=i;
sort(t+1,t+1+tot);
for(int i=1;i<=tot;i++){
int x=find(t[i].l);int y=find(t[i].r);
if(x==y)continue;
add(x,y,t[i].d);
add(y,x,t[i].d);
fa[x]=y;
}
}
void dfs(int u,int ff,int gg){
dep[u]=dep[ff]+1;f[u][0]=ff;d[u][0]=gg;
for(int i=1;i<=20;i++){
f[u][i]=f[f[u][i-1]][i-1];
d[u][i]=max(d[u][i-1],d[f[u][i-1]][i-1]);
}
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].to;
if(v==ff)continue;
dfs(v,u,edge[i].dis);
}
}
int FFF(int x,int y){
int maxn=0;
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--){
if(dep[f[x][i]]>=dep[y]){
maxn=max(maxn,d[x][i]);
x=f[x][i];
}
}
if(x==y)return maxn;
for(int i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
maxn=max(maxn,d[x][i]);
maxn=max(maxn,d[y][i]);
x=f[x][i];y=f[y][i];
}
}
return max(maxn,max(d[x][0],d[y][0]));
}
int main(){
n=read();m=read();p=read();qq=read();
for(int i=1;i<=n;i++){
scanf("%s",c+1);
for(int j=1;j<=m;j++){
a[i][j]=(c[j]=='#');
}
}
memset(head,-1,sizeof head);
memset(dis,-1,sizeof dis);
// memset(d,-1,sizeof d);
for(int i=1;i<=p;i++){
int x,y;
x=read();y=read();
vis[x][y]=i;dis[x][y]=0;
q.push(x);q.push(y);
}
bfs();
Kruskal();
for(int i=1;i<=p;i++){
if(!f[i][0])dfs(i,0,0);
}
for(int i=1;i<=qq;i++){
int x,y;
x=read();y=read();
if(find(x)!=find(y))printf("-1\n");
else printf("%d\n",FFF(x,y));
}
return 0;
}

BFS+最小生成树+倍增+LCA【bzoj】4242 水壶的更多相关文章

  1. 【bzoj4242】水壶 BFS+最小生成树+倍增LCA

    题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入 ...

  2. LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA

    非常好的一道图论问题. 显然,我们要求城市间的最小生成树,然后查询路径最大值. 然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围. 显然,如果两个城市的管辖范围没有交集的话 ...

  3. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

  4. 【bzoj3732】Network 最小生成树+倍增LCA

    题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...

  5. 训练指南 UVA - 11354(最小生成树 + 倍增LCA)

    layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true ma ...

  6. BZOJ 3732 Network —— 最小生成树 + 倍增LCA

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3732 Description 给你N个点的无向图 (1 <= N <= 15, ...

  7. BZOJ 4242: 水壶 Kruskal+BFS

    4242: 水壶 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 427  Solved: 112[Submit][Status][Discuss] D ...

  8. bzoj 4242 水壶 (多源最短路+最小生成树+启发式合并)

    4242: 水壶 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 1028  Solved: 261[Submit][Status][Discuss] ...

  9. BZOJ 4242 水壶(BFS建图+最小生成树+树上倍增)

    题意 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑 ...

随机推荐

  1. shell脚本从文件夹中递归提取文件

    需求 前两天碰到需要在十层左右的文件夹中提取文件的需求,于是写了此脚本. 如下面这样的文件结构: dir1 ├── a │ ├── b │ │ └── file1 │ └── file2 ├── c ...

  2. Python全栈 MySQL 数据库 (索引、数据导入、导出)

    ParisGabriel              每天坚持手写  一天一篇  决定坚持几年 为了梦想为了信仰    开局一张图     表字段重命名(change)   alter table 表名 ...

  3. Python全栈工程师(函数嵌套、变量作用域)

    ParisGabriel   感谢 大家的支持                                                               每天坚持 一天一篇 点个订阅 ...

  4. springboot02 Thymeleaf

    一.http协议 1. 什么是协议? 协议是交易双方共同遵守的一种约定,比如: 租房协议 , 购买协议.... 2. 什么是http协议? HTTP协议是Hyper Text Transfer Pro ...

  5. HDU 4671 Backup Plan 构造

    负载是否平衡只与前两列有关,剩下的只要与前两列不重复就随便放. 第一列我们按1-n这样循环放,第二列每次找个数最少的那个服务器放. #include <cstdio> #include & ...

  6. # ML学习小笔记—Linear Regression

    Regression Output a scalar Model:a set of function 以Linear model为例 y = b+w * $x_cp$ parameters:b,W f ...

  7. XJOI NOIP模拟题1

    第一题 分析: 开始想的是贪心,取每列均值最大一段. 应该是01分数规划,具体看代码 代码: program gold; var a:..]of int64; n,i,m,j,x:longint; f ...

  8. 【bzoj3668】[Noi2014]起床困难综合症 贪心

    原文地址:http://www.cnblogs.com/GXZlegend/p/6797090.html 题目描述 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神 ...

  9. vue实现多个元素或多个组件之间动画效果

    多个元素的过渡 <style> .v-enter,.v-leave-to{ opacity: 0; } .v-enter-acitve,.v-leave-active{ opacity: ...

  10. codeforces838D - Airplane Arrangements

    太妙啦! 我们把座位摆成一个环,在添加另一个座位,表示坐了这个位置就会有人生气,那么我们现在要求的就是没人坐它的方案数Ans,但是这个并不好求,我们发现对于每个位置,它们的Ans都是一样的,而且Ans ...