求出离每个点最近的关键点,然后用二维ST表回答正方形最大值。
将关键点分为上下两部分,以上为例:
从上到下依次考虑每一行,记录每一列往上最近的关键点的距离,那么最优决策具有单调性,可以分治求解。
时间复杂度$O(n^2\log n+t)$。
#include<cstdio>
#include<cmath>
const int N=1005,inf=N*N+N*N,BUF=27000000;
int n,m,i,j,k,x,y,z,f[N],g[N],Log[N],d[10][N][N];bool is[N][N],flag;
char Buf[BUF],*buf=Buf;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
void solve(int l,int r,int dl,int dr){
int m=(l+r)>>1,&ret=g[m],dm;
for(int i=dl;i<=dr;i++)if(~f[i]){
int t=(m-i)*(m-i)+f[i]*f[i];
if(t<ret)ret=t,dm=i;
}
if(l<m)solve(l,m-1,dl,dm);
if(r>m)solve(m+1,r,dm,dr);
}
inline int max(int a,int b){return a>b?a:b;}
inline int ask(int x,int y,int k){
int o=Log[k];
return max(max(d[o][x][y],d[o][x+k-(1<<o)][y]),max(d[o][x][y+k-(1<<o)],d[o][x+k-(1<<o)][y+k-(1<<o)]));
}
int main(){
fread(Buf,1,BUF,stdin);read(n),read(m),read(k);
for(i=2;i<=n||i<=m;i++)Log[i]=Log[i>>1]+1;
while(k--)read(x),read(y),is[x][y]=1;
for(i=0;i<=m;i++)f[i]=-1;
for(i=0;i<=n;i++){
for(j=0;j<=m;j++){
if(is[i][j])f[j]=0,flag=1;else if(~f[j])f[j]++;
g[j]=inf;
}
if(flag)solve(0,m,0,m);
for(j=0;j<=m;j++)d[0][i][j]=g[j];
}
for(flag=i=0;i<=m;i++)f[i]=-1;
for(i=n;~i;i--){
for(j=0;j<=m;j++){
if(is[i][j])f[j]=0,flag=1;else if(~f[j])f[j]++;
g[j]=inf;
}
if(flag)solve(0,m,0,m);
for(j=0;j<=m;j++)if(d[0][i][j]>g[j])d[0][i][j]=g[j];
}
for(k=1;k<10;k++)for(i=0;i+(1<<k)-1<=n;i++)for(j=0;j+(1<<k)-1<=m;j++)d[k][i][j]=max(max(d[k-1][i][j],d[k-1][i+(1<<(k-1))][j]),max(d[k-1][i][j+(1<<(k-1))],d[k-1][i+(1<<(k-1))][j+(1<<(k-1))]));
read(k);
while(k--){
read(x),read(y),read(z);
if(x<z||x+z>n||y<z||y+z>m){puts("-1");continue;}
printf("%.3f\n",std::sqrt(ask(x-z,y-z,z<<1|1)));
}
return 0;
}