您的位置:首页 > 其它

BZOJ4242:水壶(BFS & 最小生成树)

2018-01-22 18:06 288 查看

4242: 水壶

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 946  Solved: 241

[Submit][Status][Discuss]

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。

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<=H<=2000

1<=W<=2000

2<=P<=2*10^5

1<=Q<=2*10^5

1<=Ai<=H(1<=i<=P)

1<=Bi<=W(1<=i<=P)

(Ai,Bi)≠(Aj,Bj)(1<=i<j<=P)

1<=Si<Ti<=P(1<=i<=Q)

Source

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

题意:略。

思路:首先看一道题:一个无向图,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?经过“简单”的证明,“显然”该边在最小生成树上,那么我们把最小生成树建出来,倍增维护一下点间的最大边即可。本题也是一样,不过需要把建筑物的最小生成树求出来,具体做法是从每个建筑物开始BFS,两个建筑物的“势力范围”相遇时就作为一条边先存储着,最后扔到kruskal即可,那么如果建筑物A和C进行BFS时被B的“势力范围“截住了怎么办,显然AB+BC边比AC边更优,AC不要都行。拓展到图上面如BZOJ4144留坑,那题用dijk建边。

# include <iostream>
# include <cstdio>
# include <cstring>
# include <queue>
# define pb push_back
# define mp make_pair
# define pii pair<int,int>
using namespace std;
const int maxn = 2e3+13;
const int maxm = 2e5+13;
int dx[] = {0,1,0,-1}, dy[]={1,0,-1,0};
int n, m, p, q;
int fa[maxm], dep[maxm], Fa[maxm][22], dis[maxm][22];
char s[maxn][maxn];
pii sta[maxn][maxn];
vector<pii >v[maxn*maxn],g[maxm];
queue<pii >Q;
void bfs()
{
while(!Q.empty())
{
int x = Q.front().first, y = Q.front().second;
Q.pop();
for(int i=0; i<4; ++i)
{
int nx = x+dx[i];
int ny = y+dy[i];
if(nx<1||ny<1||nx>n||ny>m||s[nx][ny]=='#') continue;
if(sta[nx][ny] == mp(0,0))
sta[nx][ny] = mp(sta[x][y].first+1, sta[x][y].second), Q.push(mp(nx,ny));
else if(sta[nx][ny].second != sta[x][y].second)
v[sta[nx][ny].first+sta[x][y].first].pb(mp(sta[nx][ny].second,sta[x][y].second));
}
}
e739
}
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge_build()
{
int cnt = 0;
for(int i=1; i<=p; ++i) fa[i] = i;
for(int i=0; i<=n*m&&cnt<p-1; ++i)
{
for(int j=0; j<v[i].size()&&cnt<p-1; ++j)
{
int fu = find(v[i][j].first), fv = find(v[i][j].second);
if(fu != fv)
{
fa[fu] = fv;
++cnt;
g[v[i][j].first].pb(mp(v[i][j].second, i));
g[v[i][j].second].pb(mp(v[i][j].first, i));
}
}
}
}
void dfs(int cur, int pre)
{
Fa[cur][0] = pre;
dep[cur] = dep[pre] + 1;
for (int i=1; i<=20; ++i)
{
Fa[cur][i]=Fa[Fa[cur][i-1]][i-1];
dis[cur][i]=max(dis[cur][i-1],dis[Fa[cur][i-1]][i-1]);
}
for(int i=0; i<g[cur].size(); ++i)
{
int to = g[cur][i].first, cost = g[cur][i].second;
if(to != pre)
{
dis[to][0] = cost;
dfs(to, cur);
}
}
}

int query(int u, int v)
{
if(find(u) != find(v)) return -1;
int res = 0;
if (dep[u]<dep[v]) swap(u,v);
for (int k=20;~k;--k)
if (((dep[u]-dep[v])>>k)&1)
res=max(res,dis[u][k]),u=Fa[u][k];
if (u==v) return res;
for (int k=20;~k;--k)
if (Fa[u][k]!=Fa[v][k])
{
res=max(res,dis[u][k]);
res=max(res,dis[v][k]);
u=Fa[u][k],v=Fa[v][k];
}
return max(res,max(dis[v][0],dis[u][0]));
}
int main()
{
scanf("%d%d%d%d",&n,&m,&p,&q);
for(int i=1; i<=n; ++i)
scanf("%s",s[i]+1);
for(int i=1; i<=p; ++i)
{
int x, y;
scanf("%d%d",&x,&y);
sta[x][y] = mp(0, i);
Q.push(mp(x,y));
}
bfs();
merge_build();
for(int i=1; i<=p; ++i)
if(!dep[i])
dfs(i, 0);
while(q--)
{
int x, y;
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: