题意
JOI君所居住的IOI市以一年四季都十分炎热著称。
IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有P个,编号为1…P。
JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。
JOI君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此IOI市的市民一般都携带水壶出行。大小为x的水壶最多可以装x单位的水,建筑物里有自来水可以将水壶装满。
由于携带大水壶是一件很困难的事情,因此JOI君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。
现在给出IOI市的地图和Q个询问,第i个询问(1<=i<=Q)为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。
题解
很久以前模拟赛出的一个题。。当时不会做啊。。
过了几个月才来更正
很容易想到最小生成树,然后在树上面倍增
问题就是怎么求最小生成树
直接做
n2
n
2
的话显然不现实
我们可以考虑广搜,因为边权都是1
所以如果两个点在同一个格子遇到了,基本上就是最优值
并且肯定后来的后来的一个不用从这个格子走下去了
因为肯定如果通过这个格子相连,肯定是连先来的比较优
但是遇到是不是一定就是最优值呢?
于是就只有
n2
n
2
条边了,可以通过
也不是。。
因为扩展中的状态还是有1的相差,所以我们把边无脑丢进去,跑一次最小生成树就可以了
最后显然是一个树上倍增
但是和求LCA的姿势有一点点不一样,最后跳的一步是两条边都要看看,SB的我只看了一条。。WA了几发。。
CODE:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=2005;
const int P=200005;
int h,w,p,Q;
int mp[N][N];//这个是什么
int X[4]={-1,0,0,1};
int Y[4]={0,-1,1,0};
struct qq{int x,y,z;}E[N*N];int Num;
struct qt{int x,y,z,last;}e[P*2];int num,last[P];
queue<pair<int,int> > q;
int belong[N][N];
int d[N][N];
void Init (int x,int y,int z)
{
Num++;
E[Num].x=x;E[Num].y=y;E[Num].z=z;
}
void init (int x,int y,int z)
{
num++;
e[num].x=x;e[num].y=y;e[num].z=z;
e[num].last=last[x];
last[x]=num;
}
bool cmp (qq x,qq y){return x.z<y.z;}
int f[P];
int find (int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
void bt ()
{
sort(E+1,E+1+Num,cmp);
for (int u=1;u<=p;u++) f[u]=u;
for (int u=1;u<=Num;u++)
{
int x=find(E[u].x),y=find(E[u].y);
if (x==y) continue;
init(x,y,E[u].z);
init(y,x,E[u].z);
f[x]=y;
}
/*for (int u=1;u<=num;u++)
{
printf("%d %d %d\n",e[u].x,e[u].y,e[u].z);
system("pause");
}*/
}
int fa[P][21];
int g[P][21];
int dep[P];
void dfs (int x,int ff,int gg)
{
//printf("OZY:%d %d\n",x,gg);
dep[x]=dep[ff]+1;fa[x][0]=ff;g[x][0]=gg;
for (int u=1;u<=20;u++)
{
fa[x][u]=fa[fa[x][u-1]][u-1];
g[x][u]=max(g[x][u-1],g[fa[x][u-1]][u-1]);
}
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (y==ff) continue;
dfs(y,x,e[u].z);
}
}
int get (int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
int ans=0;
for (int u=20;u>=0;u--)
if (dep[fa[y][u]]>=dep[x])
{
ans=max(ans,g[y][u]);
y=fa[y][u];
}
if (x==y) return ans;
for (int u=20;u>=0;u--)
if (fa[x][u]!=fa[y][u])
{
ans=max(ans,g[x][u]);
ans=max(ans,g[y][u]);
x=fa[x][u];y=fa[y][u];
}
// printf("%d %d\n",x,g[x][0]);
return max(ans,max(g[x][0],g[y][0]));
}
int main()
{
/* freopen("data1.in","r",stdin);
freopen("OZY.out","w",stdout);*/
num=0;memset(last,-1,sizeof(last));
scanf("%d%d%d%d",&h,&w,&p,&Q);
char ch=getchar();
for (int u=1;u<=h;u++)
{
while (ch!='.'&&ch!='#') ch=getchar();
for (int i=1;i<=w;i++)
{
mp[u][i]=(ch=='.');
ch=getchar();
}
}
memset(d,-1,sizeof(d));
for (int u=1;u<=p;u++)
{
int x,y;
scanf("%d%d",&x,&y);//这个东西是OK的
q.push(make_pair(x,y));
belong[x][y]=u;d[x][y]=0;
}
while (!q.empty())
{
int x=q.front().first,y=q.front().second;q.pop();
/*printf("%d %d\n",x,y);
system("pause");*/
for (int u=0;u<4;u++)
{
int xx=x+X[u],yy=y+Y[u];
if (xx>=1&&xx<=h&&yy>=1&&yy<=w&&mp[xx][yy]==1)
{
if (d[xx][yy]==-1)
{
d[xx][yy]=d[x][y]+1;
belong[xx][yy]=belong[x][y];
q.push(make_pair(xx,yy));
}
else
{
if (belong[xx][yy]!=belong[x][y])
Init(belong[xx][yy],belong[x][y],d[xx][yy]+d[x][y]);
}
}
}
}
bt();
for (int u=1;u<=p;u++)
if (fa[u][0]==0)
{
// printf("%d\n",u);
dfs(u,0,0);
}
while (Q--)
{
int x,y;
scanf("%d%d",&x,&y);
if (find(x)!=find(y)) printf("-1\n");
else printf("%d\n",get(x,y));
}
return 0;
}