建议降绿
查看原帖
建议降绿
475403
Redshift_Shine楼主2024/7/11 15:29

本题可以直接使用类似 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]);
	}
}
2024/7/11 15:29
加载中...