• 【CF232E】Quick Tortoise


    题目

    题目链接:https://codeforces.com/problemset/problem/232/E
    在一个 (n imes m) 的网格上,有一些格子是障碍。给定 (Q) 个询问,每次询问是否能只通过向下走和向右走从格子 ((x_1,y_1)) 走到格子 ((x_2,y_2))
    (n,mleq 500)(Qleq 6 imes 10^5)

    思路

    简单粗暴的想法就是直接枚举每一行 (i),然后对于网格中的所有点处理出一个 bitset 表示能不能到第 (i) 行的每一个点。然后枚举询问,如果 (x_1leq ileq x_2) 的话,判断起点与终点的 bitset 是否有交即可。
    这样做是 (O(frac{n^2m^2}{omega}+frac{Qn}{omega})) 的。显然过不了。
    但是观察到对于一个询问,只需要找一个在 ([x_1,x_2]) 中的行来跑就行了。也就是说,按照上述做法处理完第 (i) 行后,第 (i+1) 行开始就没有必要考虑行不超过 (i) 的询问了。
    这启发我们采用分治。对于当前区间 ([l,r]),处理出第 (mid) 行的 bitset,然后对于这个区间内的询问,如果没有跨过第 (mid) 行,就继续分治下去做;否则判断两个 bitset 是否有交。
    时间复杂度 (O(frac{n^2mlog n}{omega}+Q(log n+frac{n}{omega})))

    代码

    #include <bits/stdc++.h>
    #define x1 WYCAKIOI
    #define x2 WYCAKIOIOI
    #define y1 WYCAKIOIOIOI
    #define y2 WYCAKIOIOIOIOI
    using namespace std;
    
    const int N=510,M=600010;
    int n,m,Q;
    char s[N][N];
    bool ans[M];
    bitset<N> f[N][N],g[N][N];
    
    struct node
    {
    	int x1,y1,x2,y2,id;
    };
    
    vector<node> a[N*4];
    
    void solve(int x,int l,int r)
    {
    	if (l>r) return;
    	for (int i=l;i<=r;i++)
    		for (int j=1;j<=m;j++)
    			f[i][j].reset(),g[i][j].reset();
    	int mid=(l+r)>>1;
    	for (int i=m;i>=1;i--)
    		if (s[mid][i]=='.')
    			f[mid][i][i]=1,f[mid][i]|=f[mid][i+1];
    	for (int i=1;i<=m;i++)
    		if (s[mid][i]=='.')
    			g[mid][i][i]=1,g[mid][i]|=g[mid][i-1];
    	for (int i=mid-1;i>=l;i--)
    		for (int j=m;j>=1;j--)
    			if (s[i][j]=='.')
    				f[i][j]|=f[i+1][j],f[i][j]|=f[i][j+1];
    	for (int i=mid+1;i<=r;i++)
    		for (int j=1;j<=m;j++)
    			if (s[i][j]=='.')
    				g[i][j]|=g[i-1][j],g[i][j]|=g[i][j-1];
    	for (int i=0;i<a[x].size();i++)
    	{
    		if (a[x][i].x2<mid) a[x*2].push_back(a[x][i]);
    		if (a[x][i].x1>mid) a[x*2+1].push_back(a[x][i]);
    		int x1=a[x][i].x1,y1=a[x][i].y1,x2=a[x][i].x2,y2=a[x][i].y2,id=a[x][i].id;
    		ans[id]=((f[x1][y1]&g[x2][y2]).count()>0);
    	}
    	a[x].clear();
    	solve(x*2,l,mid-1); solve(x*2+1,mid+1,r);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		scanf("%s",s[i]+1);
    	scanf("%d",&Q);
    	for (int i=1,x1,y1,x2,y2;i<=Q;i++)
    	{
    		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    		a[1].push_back((node){x1,y1,x2,y2,i});
    	}
    	solve(1,1,n);
    	for (int i=1;i<=Q;i++)
    		ans[i] ? cout<<"Yes
    " : cout<<"No
    ";
    	return 0;
    }
    
  • 相关阅读:
    nginx之location、rewrite配置
    nio buffer
    分布式事务
    彻底剖析RMI底层源码 、手写轻量级RMI框架
    Java RMI详解
    Java提高篇——对象克隆(复制)
    序列化
    分布式通信-tcp/ip 广播
    分布式通信-tcp/ip 单播
    php 图像处理 抠图,生成背景透明png 图片
  • 原文地址:https://www.cnblogs.com/stoorz/p/15187164.html
Copyright © 2020-2023  润新知