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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现