BZOJ4437 : [Cerc2015]Looping Labyrinth

Claris發表於2017-03-14

從$(0,0)$開始BFS$2\times10^6$步,那麼迷宮的形狀有三種:

1.走不完$2\times10^6$步,直接判定即可。

2.可以走到$(n,0)$以及$(0,m)$,那麼直接把詢問點平移到一開始的小迷宮裡即可。

3.可以沿著$(dx,dy)$這個向量達到某些左上角,那麼先三分沿向量走的步數,把詢問點平移到最近距離之後再判定。

 

#include<cstdio>
typedef long long ll;
const int N=105,M=2000010,U=(1<<24)-1;
int n,m,_,flag,dx,dy,i,j,x,y,h=1,t,q[M][2];char a[N][N];
struct E{int x,y;E*nxt;}*g[U+1],pool[M],*cur=pool,*p;
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
inline void ins(int x,int y){
  int u=((x<<9)^y)&U;
  p=cur++;p->x=x;p->y=y;p->nxt=g[u];g[u]=p;
}
inline bool ask(int x,int y){
  for(p=g[((x<<9)^y)&U];p;p=p->nxt)if(p->x==x&&p->y==y)return 1;
  return 0;
}
inline int pos(int x,int n){return (x%n+n)%n;}
inline void ext(int x,int y){
  if(t==M-1)return;
  if(!a[pos(x,n)][pos(y,m)])return;
  if(ask(x,y))return;
  q[++t][0]=x;q[t][1]=y;ins(x,y);
}
inline ll abs(ll x){return x>0?x:-x;}
inline ll dis(int x,int y,ll k){return abs(k*dx+x)+abs(k*dy+y);}
inline bool query(int x,int y){
  if(t<M-1)return ask(x,y);
  if(flag)return ask(pos(x,n),pos(y,m));
  ll l=-1000000000,r=1000000000;
  while(l+5<r){
    ll len=(r-l)/3,m1=l+len,m2=r-len;
    if(dis(x,y,m1)<dis(x,y,m2))r=m2;else l=m1;
  }
  for(;l<=r;l++)if(dis(x,y,l)<=M)if(ask(l*dx+x,l*dy+y))return 1;
  return 0;
}
int main(){
  read(n),read(m);
  for(i=0;i<n;i++)for(scanf("%s",a[i]),j=0;j<m;j++)a[i][j]=a[i][j]=='.';
  ext(0,0);
  while(h<=t){
    x=q[h][0];y=q[h++][1];
    ext(x-1,y);
    ext(x+1,y);
    ext(x,y-1);
    ext(x,y+1);
  }
  if(t==M-1){
    if(ask(n,0)&&ask(0,m))flag=1;else for(i=2;i<=t;i++){
      x=q[i][0],y=q[i][1];
      if(x%n||y%m)continue;
      dx=x,dy=y;
      break;
    }
  }
  read(_);
  while(_--)read(x),read(y),puts(query(x,y)?"yes":"no");
  return 0;
}