本题可以直接使用类似 Kruskal 最小生成树算法+瓶颈路离线求每一个询问的答案,并且求每个点上可通过的最大尺寸不需要 DP 而只需要前缀和+二分。所以可以认为本题思路简单、实现简单,无法对应蓝/紫/黑难度,所以建议降绿。
附本人实现代码:
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int N = 1e3 + 10, M = 3e5 + 10;
template <typename _Tp>
inline void read(_Tp &x)
{
char ch;
while (ch = getchar(), !isdigit(ch))
;
x = ch - '0';
while (ch = getchar(), isdigit(ch))
x = x * 10 + ch - '0';
}
template <typename _Tp, typename... _Ano>
inline void read(_Tp &x, _Ano &...ano)
{
read(x);
read(ano...);
}
int n, conn[N][N], f[N * N], m, a, b, c, d, prs[N * N], rs[N * N], mid, cr, cp, ans[M];
set<int> st[N * N];
inline int cid(int x, int y)
{
return (x - 1) * n + y;
}
inline int sm(int x, int y, int r)
{
return conn[x + r][y + r] - conn[x - r - 1][y + r] - conn[x + r][y - r - 1] + conn[x - r - 1][y - r - 1];
}
inline int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
inline void merge(int x, int y)
{
x = find(x), y = find(y);
if (x == y)
return;
f[y] = x;
if (st[x].size() < st[y].size())
st[x].swap(st[y]);
for (auto &i : st[y])
{
if (st[x].count(i))
ans[i] = cr, st[x].erase(i);
else
st[x].insert(i);
}
st[y].clear();
}
char ch;
int main()
{
read(n);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> ch;
conn[i][j] = (ch == '.') + conn[i - 1][j] + conn[i][j - 1] - conn[i - 1][j - 1];
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
a = 1, b = min(min(i, n - i + 1), min(j, n - j + 1));
while (a <= b)
{
mid = (a + b) >> 1;
if (sm(i, j, mid - 1) == (mid * 2 - 1) * (mid * 2 - 1))
a = mid + 1, rs[cid(i, j)] = mid;
else
b = mid - 1;
}
prs[cid(i, j)] = cid(i, j);
}
}
sort(prs + 1, prs + n * n + 1, [&](int x, int y)
{
if(rs[x]!=rs[y])return rs[x]>rs[y];
return x<y; });
read(m);
for (int i = 1; i <= m; i++)
{
read(a, b, c, d);
st[cid(a, b)].insert(i);
st[cid(c, d)].insert(i);
}
for (int i = 1; i <= n * n; i++)
{
cp = prs[i];
// printf("%d %d\n", cp, rs[cp]);
if (!rs[cp])
break;
cr = rs[cp] * 2 - 1;
f[cp] = cp;
if (cp > n and f[cp - n])
merge(cp, cp - n);
if (cp + n <= n * n and f[cp + n])
merge(cp, cp + n);
if (cp % n and f[cp + 1])
merge(cp, cp + 1);
if (cp % n != 1 and f[cp - 1])
merge(cp, cp - 1);
}
for (int i = 1; i <= m; i++)
{
printf("%d\n", ans[i]);
}
}