【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. Python全栈工程师(for、列表)

    ParisGabriel     Python 入门基础         for:用来遍历可迭代对象的数据元素可迭代对象是指以此获取数据元素的对象可迭代对象包括:字符串 str 列表 list元组 t ...

  2. codeblocks17.12 debug 报错:ERROR: You need to specify a debugger program in the debuggers's settings.

    DebugERROR: You need to specify a debugger program in the debuggers's settings.(For MinGW compilers, ...

  3. Spring Web MVC 笔记

    Spring Web MVC 流程 Dispatcher Servlet 这是一个前端分派 Servlet(前端控制器模式),外部所有的请求都会先到达这里,然后由其将请求分派给其他组件进行实际的处理. ...

  4. 微信小程序--获取form表单初始值提交数据

    <form bindsubmit="formSubmit"> <view class="txt"> <view class=&qu ...

  5. android之SlideMenu双向滑动

    开始动手之前先来讲一下实现原理,在一个Activity的布局中需要有三部分,一个是左侧菜单的布局,一个是右侧菜单的布局,一个是内容布局.左侧菜单居屏幕左边缘对齐,右侧菜单居屏幕右边缘对齐,然后内容布局 ...

  6. 201621123033 《Java程序设计》第6周学习总结

    第六次作业 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 2. 书面作业 1. clone方法 ...

  7. 【bzoj1511】[POI2006]OKR-Periods of Words KMP-next数组

    原文地址:http://www.cnblogs.com/GXZlegend/p/6827027.html 题目描述 一个串是有限个小写字符的序列,特别的,一个空序列也可以是一个串. 一个串P是串A的前 ...

  8. Maven项目消除奇怪的红叉

    当项目截然无误,然则Eclipse总是出现红叉的时候,右键点击项目->Maven->Update Project-,进而纠正之.很简答的操作. 木头大哥所发的文章均基于自身实践,各位江湖好 ...

  9. hibernate中Configuration类的作用

    问题:我们在获得一个SessionFactory对象的时候经常是写下面这行代码: SessionFactory sessionFactory = new Configuration().configu ...

  10. Codevs 2080 特殊的质数肋骨

      题目描述 Description 农民约翰的母牛总是产生最好的肋骨. 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们. 农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋 ...