CF232E Quick Tortoise 题解
考虑离线猫树分治。分治函数 solve(l,r) 表示将所有询问区间 完全包含于这个区间的询问区间答案处理出来。
考虑在 两侧的递归处理,现在要考虑的是 的答案。
考虑 能到 的充分必要条件是,存在 上的一个点,使得能从 到这个点,且可以从这个点到 。
注意到我们可以用两个二维 bitset,f[i][j] 和 g[i][j],分别表示 能到的 的所有位置。区别是,f 统计的是 的 ,g 统计的是 的。这两个都可以通过确定循环顺序做到正确复杂度。
询问答案时,用 & 之后 count 即可。
同阶,复杂度 。可以通过。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <bitset>
#include <stack>
using namespace std;
const int N = 505;
const int Q = 6e5 + 5;
struct Query
{
int Y1, X2, Y2, id;
Query() = default;
Query(int id, int Y1, int X2, int Y2)
: id(id), Y1(Y1), X2(X2), Y2(Y2)
{
}
bool operator==(const Query& other) const
{
return id == other.id && Y1 == other.Y1 && X2 == other.X2 && Y2 == other.Y2;
}
};
vector<Query> v[N];
int n, m, q;
char c[N][N];
bitset<N> f[N][N], g[N][N];
int cnt[N];
int ans[Q];
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
memset(ans, -1, sizeof ans);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> c[i][j];
}
}
cin >> q;
for (int i = 1; i <= q; i++)
{
int X1, Y1, X2, Y2;
cin >> X1 >> Y1 >> X2 >> Y2;
v[X1].emplace_back(Query(i, Y1, X2, Y2));
if (X2 >= X1 && Y2 >= Y1) continue;
ans[i] = 0;
}
for (int i = 1; i <= n; i++) sort(v[i].begin(), v[i].end(), [&](const auto& x, const auto& y) {return x.X2 < y.X2; });
auto solve = [&](auto self, int l, int r)
{
if (l == r)
{
for (int i = 1; i <= m; i++) cnt[i] = cnt[i - 1] + (c[l][i] == '#');
auto i1 = upper_bound(v[l].begin(), v[l].end(), Query(0, 0, l - 1, 0), [&](const auto& x, const auto& y) {return x.X2 < y.X2; });
for (; i1 != v[l].end(); ++i1)
{
if ((*i1).X2 != l) return;
if ((*i1).Y2 < (*i1).Y1) continue;
int id = (*i1).id;
ans[id] = !(cnt[(*i1).Y2] - cnt[(*i1).Y1 - 1]);
}
return;
}
int mid = l + r >> 1;
self(self, l, mid);
self(self, mid + 1, r);
for (int j = m + 1; j >= 0; j--)
{
for (int i = mid + 1; i >= l - 1; i--) f[i][j].reset();
}
for (int j = m; j >= 1; j--)
{
for (int i = mid; i >= l; i--)
{
f[i][j].reset();
if (i == mid)
{
if (c[i][j] == '.')
{
f[i][j][j] = 1;
f[i][j] |= f[i][j + 1];
}
continue;
}
if (c[i][j] == '.')
{
f[i][j] = f[i][j + 1] | f[i + 1][j];
}
}
}
for (int i = mid; i <= r + 1; i++)
{
for (int j = 0; j <= m + 1; j++) g[i][j].reset();
}
for (int j = 1; j <= m; j++)
{
for (int i = mid + 1; i <= r; i++)
{
if (i == mid + 1)
{
if (c[i][j] == '.')
{
if (c[mid][j] == '.') g[i][j][j] = 1;
g[i][j] |= g[i][j - 1];
}
continue;
}
if (c[i][j] == '.')
{
g[i][j] = g[i - 1][j] | g[i][j - 1];
}
}
}
for (int i = l; i <= mid; i++)
{
// (mid,r]
auto it = upper_bound(v[i].begin(), v[i].end(), Query(0, 0, mid, 0), [&](const auto& x, const auto& y) {return x.X2 < y.X2; });
for (; it != v[i].end(); ++it)
{
Query p = *it;
if (p.X2 <= mid || p.X2 > r) break;
if (~ans[p.id]) continue;
//cout << "!!!!!: " << l << " " << r << " " << ((g[p.X2][p.Y2]).count()) << "\n";
ans[p.id] = (int)((bool)((f[i][p.Y1] & g[p.X2][p.Y2]).count()));
}
}
};
solve(solve, 1, n);
for (int i = 1; i <= q; i++)
{
cout << (ans[i] ? "Yes\n" : "No\n");
}
return 0;
}

浙公网安备 33010602011771号