F. Robots
题意:
给定n * m的矩阵,其中有一些格子无法经过,存在三种类型的移动方式。
1.(x, y) —>(x + 1, y )
2.(x,y) —>(x, y + 1)
3.(x, y) —>(x + 1, y) || (x, y + 1)
给定q个查询,每次查询询问某种移动方式是否能从(x1, y1) --> (x2, y2)
n
,
m
<
=
500
,
q
<
=
5
e
5
n , m <= 500, q <= 5e5
n,m<=500,q<=5e5
思路:
考虑到q次查询,如若对每次进行暴力dp求解,时间复杂度为O(q * n * m) >> O(n * m * n * m)
预处理离线肯定是优于每次在线查询。
考虑暴力f[i][j][k][t]:从起点(i,j)是否能到达(k,t)。时间复杂度O(n * m * n * m)也会TLE。
如果之前写过 可达性统计, 就会很容易想到存储一个用bitset存储一个可达图。
假设当前点(i,j)可经过,那么所有能到达(i,j-1) 和 (i - 1, j)的点的起点也可以到达该点。相当于是维护以当前点为终点,其左上有多少点可到达该点的一个图。
mm[i][j] == 1表示不可经过。
bitset<N * N> f[i][j]
i
f
(
m
m
[
i
]
[
j
]
=
=
0
)
f
[
i
]
[
j
]
[
(
i
−
1
)
∗
m
+
j
)
=
1
,
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
o
r
f
[
i
]
[
j
−
1
]
if(mm[i][j] == 0) \;f[i][j][(i - 1) * m + j) = 1, f[i][j] = f[i - 1][j] \;or \;f[i][j - 1]
if(mm[i][j]==0)f[i][j][(i−1)∗m+j)=1,f[i][j]=f[i−1][j]orf[i][j−1]
e
l
s
e
f
[
i
]
[
j
]
.
r
e
s
e
t
(
)
else \;f[i][j].reset()
elsef[i][j].reset() //说明当前点的左上区域无点可到达当前点。
code:
int mm[maxn][maxn];
struct note{
int id;
int ty;
int x;
int y;
};
vector <note> alls[maxn][maxn];
bitset <maxn * maxn> f[maxn];
bool ans[N];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
scanf("%1d", &mm[i][j]);
}
int q;
scanf("%d", &q);
for(int i = 1 ; i <= q ; i ++)
{
int t, x1, y1, x2, y2;
scanf("%d %d %d %d %d", &t, &x1, &y1, &x2, &y2);
alls[x2][y2].push_back({i, t, x1, y1});
}
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
{
if(mm[i][j] == 0)
{
f[j][(i - 1) * m + j] = 1;
f[j] |= f[j - 1]; //当前层
f[j] |= f[j]; // 上一层
}
else
f[j].reset();
for(auto t : alls[i][j])
{
if(t.ty == 1)
{
if(t.y == j) //同列
ans[t.id] = f[j][(t.x - 1) * m + t.y];
}
else if(t.ty == 2)
{
if(t.x == i) //同行
ans[t.id] = f[j][(t.x - 1) * m + t.y];
}
else
{
ans[t.id] = f[j][(t.x - 1) * m + t.y];
}
}
}
}
for(int i = 1 ; i <= q ; i ++)
{
if(ans[i]) printf("yes\n");
else printf("no\n");
}
return 0;
}