• 题解 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;
    }
    
  • 相关阅读:
    跟我一起在Win10中用VMware安装Ubuntu
    跟我一起安装vmware
    关于vue项目报错:this relative module was not found
    【error】vue-style-loader didn't discriminate between server and client
    [Vue warn]: Error in beforeCreate hook: "Error: Cannot find module './index.vue?vue&type=style&index=0&lang=scss&'"
    JavaScript数据可视化编程书籍上面的例子(flotr2)
    ExecuteNonQuery和ExecuteScalar的区别
    Datatable添加数据,提示该行已经属于另一个表的解决方法
    利用反射动态调用类成员
    c#用picturebox显示多页TIF
  • 原文地址:https://www.cnblogs.com/lhm-/p/13519492.html
Copyright © 2020-2023  润新知