BZOJ4242 水壶

Time Limit: 50 Sec Memory Limit: 512 MB

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\leq i\leq H\))有一个长度为W的字符串,每个字符都是’.’或’#’之一,’.’表示这个位置是建筑物或原野,’#’表示这个位置是墙壁。

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

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

Output

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

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

Sample Input

5 5 4 4
.....
..##.
.#...
..#..
.....
1 1
4 2
3 3
2 5
1 2
2 4
1 3
3 4

Sample Output

3
4
4
2

HINT

\(1\leq H\leq 2000\)

\(1\leq W \leq 2000\)

\(2\leq P\leq 2\times10^5\)

\(1\leq Q\leq 2\times 10^5\)

\(1\leq A_i\leq H(1\leq i\leq P)\)

\(1\leq B_i\leq W(1\leq i\leq P)\)

\((A_i,B_i)≠(A_j,B_j)(1\leq i<j\leq P)\)

\(1\leq Si<Ti\leq P(1\leq i\leq Q)\)

Source

JOI 2013~2014 春季training合宿 竞技2 By PoPoQQQ

Solution

嗯这道题目第一眼看上去就是货车运输的清奇的画风啊。

问题是如何建边。

你肯定不能把一共\(W\times H\)个点放进图里面来建边吧。这样跑最小生成树。。。不太了解。Update:这个是我一开始很傻的想法,现在突然发先这样好像就是错的,根本做不了。

我们只把\(P\)个点放过来建边。显然两个点之间的边就应该是在地图中的最短距离吧。但是我们需要把\(P^2\)组最短距离缩减成一棵树。

所以我们对一共\(P\)个建筑物同时开始BFS,然后对于每个空地,第一个BFS到它的建筑物就记录一下,后面的所有BFS到之的建筑物都和第一个BFS到的连边,边权为距离即可。然后我们得到一个图,跑最小生成树就可以了。因为这个边权不超过\(W*H\),所有可以用vector或者链表按边权存一下边,省去了跑排序的\(\log\)

为什么不用把所有点之间全都连边就可以保证正确性呢?其实这个结论很显然啊。因为第一个BFS到这个点的一定是离他最近的,顺边去最近的补水不是常规操作吗。。。反正也没要求走最短路。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
template<typename A>inline void read(A&a){a=0;char c=0;int f=1;while(c<'0'||c>'9')(c=getchar())=='-'?f=-1:0;while(c>='0'&&c<='9')a=(a<<3)+(a<<1)+c-'0',c=getchar();f==-1?a=-a:0;}
char buf[30];template<typename A>inline void write(A a){if(a<0)putchar('-'),a=-a;int top=0;if(!a)buf[top=1]='0';while(a)buf[++top]=a%10+'0',a/=10;while(top)putchar(buf[top--]);}
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}

const int H=2000+7,N=2e5+7,LOG=19,fx[]={0,0,1,0,-1},fy[]={0,1,0,-1,0};
int w,h,n,Q,x,y,del[H][H],vis[H][H],f[N][LOG],s[N][LOG],dep[N],mxd;char a[H][H];
struct Edge{int to,ne,w;}g[N<<1];int head[N],tot;
inline void Addedge(int x,int y,int z){g[++tot].to=y,g[tot].w=z;g[tot].ne=head[x];head[x]=tot;}
struct Graph{int x,y,z;};vector<Graph>G[H*H];

struct Node{int x,y,fr,s;}q[H*H];int hd,tl;
inline void BFS(){
	while(hd<tl){
		Node t=q[++hd];
		for(register int i=1;i<=4;++i){
			int px=t.x+fx[i],py=t.y+fy[i];
			if(px<1||px>h||py<1||py>w||a[px][py])continue;
			if(vis[px][py]>0&&vis[px][py]!=t.fr){G[del[px][py]+t.s].push_back(Graph{vis[px][py],t.fr}),SMAX(mxd,del[px][py]+t.s);continue;}else if(vis[px][py])continue;
			vis[px][py]=t.fr;del[px][py]=t.s+1;q[++tl]=Node{px,py,t.fr,t.s+1};
		}
	}
}

int fa[N];
inline int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
inline void Union(int x,int y){x=Find(x),y=Find(y),fa[y]=x;}
inline void Kruskal(){
	for(register int i=1;i<=n;++i)fa[i]=i;
	for(register int i=0,cnt=0;i<=mxd;++i){//错误笔记:从0开始循环,允许有的边权为0 
		int len=G[i].size();
		for(register int j=0;j<len;++j){
			int x=Find(G[i][j].x),y=Find(G[i][j].y);if(x==y)continue;
			Union(x,y);Addedge(G[i][j].x,G[i][j].y,i),Addedge(G[i][j].y,G[i][j].x,i);++cnt;if(cnt==n-1)continue;
		}
	}
}

inline void DFS(int x,int fa=0){
	f[x][0]=fa;dep[x]=dep[fa]+1;for(register int i=1;i<LOG;++i)f[x][i]=f[f[x][i-1]][i-1],s[x][i]=max(s[x][i-1],s[f[x][i-1]][i-1]);
	for(register int i=head[x];i;i=g[i].ne)if(g[i].to!=fa)s[g[i].to][0]=g[i].w,DFS(g[i].to,x);
}
inline int LCA(int x,int y){
	if(dep[x]<dep[y])x^=y^=x^=y;int ans=0;
	for(register int i=LOG-1;i>=0;--i)if(dep[f[x][i]]>=dep[y])SMAX(ans,s[x][i]),x=f[x][i];
	if(x==y)return ans;
	for(register int i=LOG-1;i>=0;--i)if(f[x][i]!=f[y][i])SMAX(ans,s[x][i]),SMAX(ans,s[y][i]),x=f[x][i],y=f[y][i];
	return max(ans,max(s[x][0],s[y][0]));
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("BZOJ4242.in","r",stdin);freopen("BZOJ4242.out","w",stdout);
#endif
	read(h),read(w),read(n),read(Q);
	for(register int i=1;i<=h;++i){
		scanf("%s",a[i]+1);
		for(register int j=1;j<=w;++j)a[i][j]=a[i][j]=='#';
	}
	for(register int i=1;i<=n;++i){read(x),read(y);vis[x][y]=i;q[++tl]=Node{x,y,i,0};}
	BFS();Kruskal();for(register int i=1;i<=n;++i)if(!dep[i])DFS(i);
	for(register int i=1;i<=Q;++i){
		read(x),read(y);
		write(Find(x)==Find(y)?LCA(x,y):-1),putchar('\n');
	}
}
posted @ 2018-10-25 10:50  hankeke303  阅读(227)  评论(1编辑  收藏  举报