传送门
显然在求出最短距离之后是可以二分答案的。
我们考虑按照每列来计算每个点的最短距离。
显然可以发现,对于该列来说,每一行都可能有一个到该列最近的点,并且我们发现,如果某一行有两个坏点的话,假设分别为A,B,并且A到该列的距离最近,那么B显然不会对这一列的dis有任何影响。
所以我们显然可以在求之前预处理一下每一行的如果存在坏点的那个最近的坏点的坐标。
接下来,我们讨论坏点k,l,设我们要更新的点是(x,y)
如果k优于l,那么我们不妨列一下式子。
#include
#include
#include
#include
#include
#include
#include
#define N 1100
using namespace std;
int n,m,num,c[N][N];
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct node{
int x,y;
node(){}
node(int _x,int _y):x(_x),y(_y){}
friend bool operator ==(node a,node b){
return a.x==b.x&&a.y==b.y;
}
}a[N*N],S,T;
int dis[N][N];
bool vis[N][N];
node q[N],nq[N];
int ask(node a,node b){
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
double slop(node a,node b,int tmpx){
return 1.0*(a.x*a.x-b.x*b.x+2*tmpx*b.x-2*tmpx*a.x)/(a.y-b.y)+a.y+b.y;
}
void pre(){
memset(dis,60,sizeof(dis));
for (int i=1;i<=num;i++)
dis[a[i].x][a[i].y]=0;
for (int i=1;i<=n;i++){
int h=1,t=0;
for (int j=1;j<=m;j++){
int l=1,r=c[j][0],ans=l;
while (l<=r){
int mid=(l+r)/2;
if (c[j][mid]<=i) ans=mid,l=mid+1;
else r=mid-1;
}
if (ans+1<=c[j][0]&&abs(c[j][ans+1]-i)<abs(i-c[j][ans]))
ans++;
if (ans<=c[j][0]){
node tmp;
tmp.x=c[j][ans],tmp.y=j;
q[++t]=tmp;
}
}
if (t==1){
for (int j=1;j<=m;j++)
dis[i][j]=ask(node(i,j),q[t]);
continue;
}
int T=t; t=0;
for (int j=1;j<=T;j++){
while (hq[j],nq[t],i)<=slop(nq[t],nq[t-1],i)) t--;
if (h>=t||slop(q[j],nq[t],i)>slop(nq[t],nq[t-1],i))
nq[++t]=q[j];
}
for (int j=1;j<=m;j++){
int l=2,r=t,ans=1;
while (l<=r){
int mid=(l+r)/2;
if (slop(nq[mid],nq[mid-1],i)<=2*j)
ans=mid,l=mid+1;
else r=mid-1;
}
dis[i][j]=min(dis[i][j],ask(node(i,j),nq[ans]));
}
}
}
bool check(int x){
memset(vis,0,sizeof(vis));
queue q;
while (!q.empty()) q.pop();
if (dis[S.x][S.y]>=x)
q.push(S),vis[S.x][S.y]=1;
while (!q.empty()){
node u=q.front(); q.pop();
for (int i=0;i<4;i++){
node tmp;
tmp.x=u.x+d[i][0];
tmp.y=u.y+d[i][1];
if (tmp.x<1||tmp.x>n||tmp.y<1||tmp.y>m) continue;
if (dis[tmp.x][tmp.y]>=x&&!vis[tmp.x][tmp.y]){
vis[tmp.x][tmp.y]=1;
q.push(tmp);
}
}
}
return vis[T.x][T.y];
}
int main(){
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);
scanf("%d",&num);
for (int i=1;i<=num;i++){
scanf("%d%d",&a[i].x,&a[i].y);
c[a[i].y][++c[a[i].y][0]]=a[i].x;
}
for (int i=1;i<=m;i++)
sort(c[i]+1,c[i]+c[i][0]+1);
pre();
int l=0,r=n*n+m*m,ans=0;
while (l<=r){
int mid=(l+r)/2;
if (check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
}