题意:给一张n*m的图,上面有若干障碍物,现在有3种机器人,1只能往下走,2只能往右走,3可以往下往右走,对于q次询问,回答对应机器人是否能到达目的地。
思路:赛场上想到了要分治,但是具体处理有问题,也没想到用bitset优化DP,所以没过。
题解:对于q次询问,1和2类型的机器人我们可以预先处理掉,然后对于类型三的机器人,我们对其中一维进行分治。
将区域分成两半,然后开一个DP数组,存储从x,y开始到达Mid分界线的可达性。显然正常开数组需要三维。
dp[x][y][z]表示x,y开始能否到达mid,z,但是这里可以利用bitset优化。
然后我们就能获得起点到分界线与终点到分界线的可达情况,进行一次与操作,如果互相可达,那么与之后的数一定不等于0。
对于在分界线两边的询问,我们这样就处理完了,对于分界线一边的点,我们继续分治就行。
时间复杂度qlogn+n^3logn/32
下附代码:

#include<bits/stdc++.h> using namespace std; bool g[505][505]; int ed1[505][505],ed2[505][505]; char s[505]; int res[500005]; int n,m,q; struct node{ int x1,y1,x2,y2,pos; }; vector<node> v; bitset<505> dp[505][505]; void solve(int l,int r,vector<node> &v){ if (l==r){ for (auto x:v){ int st=x.y1,ed=x.y2; if (ed1[l][ed]-ed1[l][st-1]==0) res[x.pos]=1; else res[x.pos]=0; } v.clear(); return; } int mid=(l+r)>>1; for (int i=m; i>=1; i--){ dp[mid][i].reset(); if (!g[mid][i]){ dp[mid][i].set(i); dp[mid][i]|=dp[mid][i+1]; } } for (int i=1; i<=m; i++){ dp[mid+1][i].reset(); if (!g[mid+1][i]){ dp[mid+1][i].set(i); dp[mid+1][i]|=dp[mid+1][i-1]; } } for (int i=m; i>=1; i--){ for (int j=mid-1; j>=l; j--){ if (g[j][i]){ dp[j][i].reset(); continue; } dp[j][i]=dp[j][i+1]|dp[j+1][i]; } } for (int i=1; i<=m; i++){ for (int j=mid+2; j<=r; j++){ if (g[j][i]){ dp[j][i].reset(); continue; } dp[j][i]=dp[j][i-1]|dp[j-1][i]; } } vector<node> vl,vr; for (auto x:v){ if(x.x1<=mid && x.x2>mid){ if ((dp[x.x1][x.y1]&dp[x.x2][x.y2]).count()) res[x.pos]=1; } else if(x.x2<=mid) vl.push_back(x); else vr.push_back(x); } v.clear(); solve(l,mid,vl); solve(mid+1,r,vr); } int main(){ scanf("%d%d",&n,&m); for (int i=1; i<=n; i++){ scanf("%s",s); for (int j=0; j<m; j++){ g[i][j+1]=s[j]-'0'; ed1[i][j+1]=ed1[i][j]+g[i][j+1]; ed2[i][j+1]=ed2[i-1][j+1]+g[i][j+1]; } } scanf("%d",&q); int p=0; int tt=q; while (q--){ int z,a,b,c,d; scanf("%d%d%d%d%d",&z,&a,&b,&c,&d); if (z==1){ if (b!=d || a>c){ res[++p]=0; } else { if (ed2[c][b]-ed2[a-1][b]==0){ res[++p]=1; } else res[++p]=0; } } else if (z==2){ if (a!=c || b>d){ res[++p]=0; } else { if (ed1[a][d]-ed1[a][b-1]==0){ res[++p]=1; } else res[++p]=0; } } else { if (a>c || b>d){ res[++p]=0; } else { v.push_back({a,b,c,d,++p}); } } } solve(1,n,v); for (int i=1; i<=tt; i++){ if (res[i]) printf("yes "); else printf("no "); } }