zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    STL源码剖析之_allocate函数
    PAT 1018. Public Bike Management
    PAT 1016. Phone Bills
    PAT 1012. The Best Rank
    PAT 1014. Waiting in Line
    PAT 1026. Table Tennis
    PAT 1017. Queueing at Bank
    STL源码剖析之list的sort函数实现
    吃到鸡蛋好吃,看看是哪只母鸡下的蛋:好用的Sqlite3
    cJSON
  • 原文地址:https://www.cnblogs.com/stoorz/p/15187164.html
Copyright © 2011-2022 走看看