题解 CF232E 【Quick Tortoise】

首先对所有询问进行离线处理,因为是网格图,所以考虑用分治来解决。

([1,n]) 进行分治,对于区间 ([l,r]),在 (mid) 两侧的点对互相要到达一定会经过 (mid) 所在的直线,因此每次处理出 (f_{i,j,k})(g_{i,j,k})(f_{i,j,k}) 为点 ((i,j)) 是否能到达点 ((k,mid))(g_{i,j,k}) 为点 ((k,mid)) 是否能到达点 ((i,j))

对于分别在 (mid) 两侧的点对,直接通过 (f,g) 取并即可回答询问,只在一侧的点对就继续分治下去。

(n,m) 看作同阶,得复杂度为 (O((n^3+q)log n)),无法接受,对 (f,g)(bitset) 来优化后复杂度为 (O((frac{n^3}{w}+q)log n)),即可通过。

#include<bits/stdc++.h>
#define maxn 510
#define maxm 600010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,t;
bool ans[maxm];
char w[maxn][maxn];
bitset<maxn> f[maxn][maxn],g[maxn][maxn];
struct query
{
    int x1,y1,x2,y2,id;
}q[maxm],q1[maxm],q2[maxm];
void solve(int L,int R,int l,int r)
{
    if(L>R||l>r) return;
    int cnt1=0,cnt2=0,mid=(l+r)>>1;
    for(int i=mid;i>=l;--i)
    {
        for(int j=m;j;--j)
        {
            if(w[i][j]=='#') continue;
            f[i][j].reset(),f[i][j][j]=(i==mid);
            if(i+1<=mid&&w[i+1][j]=='.') f[i][j]|=f[i+1][j];
            if(j+1<=m&&w[i][j+1]=='.') f[i][j]|=f[i][j+1];
        }
    }
    for(int i=mid;i<=r;++i)
    {
        for(int j=1;j<=m;++j)
        {
            if(w[i][j]=='#') continue;
            g[i][j].reset(),g[i][j][j]=(i==mid);
            if(i-1>=mid&&w[i-1][j]=='.') g[i][j]|=g[i-1][j];
            if(j-1>=1&&w[i][j-1]=='.') g[i][j]|=g[i][j-1];
        }
    }
    for(int i=L;i<=R;++i)
    {
        if(q[i].x2<mid) q1[++cnt1]=q[i];
        if(q[i].x1>mid) q2[++cnt2]=q[i];
        if(q[i].x1<=mid&&q[i].x2>=mid)
            ans[q[i].id]=(f[q[i].x1][q[i].y1]&g[q[i].x2][q[i].y2]).any();
    }
    for(int i=1;i<=cnt1;++i) q[L+i-1]=q1[i];
    for(int i=1;i<=cnt2;++i) q[L+cnt1+i-1]=q2[i];
    solve(L,L+cnt1-1,l,mid-1),solve(L+cnt1,L+cnt1+cnt2-1,mid+1,r);
}
int main()
{
    read(n),read(m);
    for(int i=1;i<=n;++i) scanf("%s",w[i]+1);
    read(t);
    for(int i=1;i<=t;++i)
        read(q[i].x1),read(q[i].y1),read(q[i].x2),read(q[i].y2),q[i].id=i;
    solve(1,t,1,n);
    for(int i=1;i<=t;++i) puts(ans[i]?"Yes":"No");
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/13519492.html