CF232E Quick Tortoise
本文最后更新于:March 15, 2022 pm
先将询问离线下来分治,设当前分治区间为 $[l,r]$ , $mid = (l + r) >> 1$,考虑处理左上角到右下角的询问,剩下的分到左右两边。
由于路径必然经过 $y=mid$ 这条直线,考虑记 $g1(i,j,k) = 1/0$ 表示 $(i,j)$ 能否走到 $(k,mid)$, $g2(i,j,k) = 1/0$ 表示 $(k,mid)$ 能否走到 $(i,j)$,
然后转移用 $bitset$ 优化一下就可以做到 $\mathrm{O(\dfrac {n^2m\log m}{\omega} + \dfrac {qn}{\omega})}$ 。
实现的时候 $(i,j)$ 的意义是反过来的((
$\text{Code:}$
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
const int maxn = 500 + 5;
const int maxq = 6e5 + 5;
int n, m, ans[maxq]; char c[maxn][maxn];
struct _ques {
int xl, yl, xr, yr, id;
} qr[maxq], q0[maxq], q1[maxq];
int ck[maxn];
bitset<maxn> g1[maxn][maxn], g2[maxn][maxn];
void solve(int l, int r, int L, int R) {
if (L > R) return;
if (l == r) {
for (int i = 1; i <= n; i++) ck[i] = ck[i - 1] + (c[i][r] == '#');
for (int i = L; i <= R; i++)
if (ck[qr[i].xr] == ck[qr[i].xl - 1]) ans[qr[i].id] = 1;
return;
}
int mid = (l + r) >> 1, c0 = 0, c1 = 0;
for (int j = l; j <= r; j++)
for (int i = 1; i <= n; i++) g1[j][i].reset(), g2[j][i].reset();
for (int i = 1; i <= n; i++) {
if (c[i][mid] == '.') {
if (i) g2[mid][i] |= g2[mid][i - 1];
g2[mid][i].set(i);
}
for (int j = mid; j <= r; j++) {
if (c[i][j] == '#') continue;
if (i) g2[j][i] |= g2[j][i - 1];
if (j > mid) g2[j][i] |= g2[j - 1][i];
}
}
for (int i = n; i >= 1; i--) {
if (c[i][mid] == '.') {
if (i < n) g1[mid][i] |= g1[mid][i + 1];
g1[mid][i].set(i);
}
for (int j = mid; j >= l; j--) {
if (c[i][j] == '#') continue;
if (i < n) g1[j][i] |= g1[j][i + 1];
if (j < mid) g1[j][i] |= g1[j + 1][i];
}
}
for (int i = L; i <= R; i++)
if (qr[i].yr <= mid) q0[++c0] = qr[i];
else if (qr[i].yl > mid) q1[++c1] = qr[i];
else {
// printf("%d %d %d\n", qr[i].id, g1[qr[i].yl][qr[i].xl].count(), g2[qr[i].yr][qr[i].xr].count());
// for (int j = 1; j <= n; j++) printf("%d ", g1[qr[i].yl][qr[i].xl][j] ? 1 : 0); puts("");
// for (int j = 1; j <= n; j++) printf("%d ", g2[qr[i].yr][qr[i].xr][j] ? 1 : 0); puts("");
if ((g1[qr[i].yl][qr[i].xl] & g2[qr[i].yr][qr[i].xr]).count()) ans[qr[i].id] = 1;
}
for (int i = 1; i <= c0; i++) qr[L + i - 1] = q0[i];
for (int i = 1; i <= c1; i++) qr[R - i + 1] = q1[i];
solve(l, mid, L, L + c0 - 1);
solve(mid + 1, r, R - c1 + 1, R);
}
int main() {
n = read(); m = read();
for (int i = 1; i <= n; i++) scanf("%s", c[i] + 1);
int q = read();
for (int i = 1; i <= q; i++) {
int x = read(), y = read();
qr[i].xl = x; qr[i].yl = y;
x = read(), y = read();
qr[i].xr = x; qr[i].yr = y;
qr[i].id = i;
}
solve(1, m, 1, q);
for (int i = 1; i <= q; i++) puts(ans[i] ? "Yes" : "No");
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!