题目大意:
分析:
考虑离线:
设
f
i
,
j
f_{i,j}
fi,j表示
点
(
i
,
j
)
点(i,j)
点(i,j)为右下角最多能向左上拓展多长的正方形,其对角线长度即为
f
i
,
j
f_{i,j}
fi,j
任意相邻两点
u
,
v
u,v
u,v间建边
(
u
,
v
,
w
)
(u,v,w)
(u,v,w),
w
=
m
i
n
(
f
u
,
f
v
)
w=min(f_u,f_v)
w=min(fu,fv),然后将这些边存起来按
w
w
w降序排列
将询问
(
x
1
,
y
1
,
x
2
,
y
2
,
w
)
(x_1,y_1,x_2,y_2,w)
(x1,y1,x2,y2,w)存起来按
w
w
w降序排列
枚举询问,当前是第
i
i
i大
w
w
w对应的询问,
将
>
=
w
i
>=w_i
>=wi的所有
(
u
,
v
,
w
)
(u,v,w)
(u,v,w)解封,然后判断
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)与
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2)是否连通,
判断是否连通可以用并查集,每解封一条边就用并查集将边的两个点的集合合并
PS:注意考虑 f x 1 , y 1 < w , f x 2 , y 2 < w f_{x_1,y_1}<w,f_{x_2,y_2}<w fx1,y1<w,fx2,y2<w的情况
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define M 100005
#define N 1005
using namespace std;
struct Node { int u, v, w; }e[2*N*N];
struct Aske { int id, ax, ay, bx, by, lim; }c[M];
int id[N][N], f[N][N], a[N][N], fa[N*N], ans[M], n, m, q, tot, cnt;
char s[N];
bool cmp1(Node aa, Node bb) { return aa.w > bb.w; }
bool cmp2(Aske aa, Aske bb) { return aa.lim > bb.lim; }
int find(int x) { return (fa[x] == x ? x : (fa[x] = find(fa[x]))); }
void merge(int id)
{
int pos1 = find(e[id].u);
int pos2 = find(e[id].v);
if (pos1 != pos2) fa[pos1] = pos2;
}
int main()
{
freopen("square.in", "r", stdin);
freopen("square.out", "w", stdout);
scanf("%d %d %d", &n, &m, &q);
rep(i, 1, n)
{
scanf("%s", s + 1);
rep(j, 1, m) a[i][j] = s[j] - '0', id[i][j] = ++tot, fa[id[i][j]] = tot;
}
rep(i, 1, n)
rep(j, 1, m)
if (!a[i][j]) f[i][j] = min(f[i - 1][j - 1], min(f[i][j - 1], f[i - 1][j])) + 1;
rep(i, 1, n)
rep(j, 1, m - 1) e[++cnt].u = id[i][j], e[cnt].v = id[i][j + 1], e[cnt].w = min(f[i][j], f[i][j + 1]);
rep(i, 1, m)
rep(j, 1, n - 1) e[++cnt].u = id[j][i], e[cnt].v = id[j + 1][i], e[cnt].w = min(f[j][i], f[j + 1][i]);
sort(e + 1, e + cnt + 1, cmp1);
rep(i, 1, q) scanf("%d %d %d %d %d", &c[i].ax, &c[i].ay, &c[i].bx, &c[i].by, &c[i].lim), c[i].id = i;
sort(c + 1, c + q + 1, cmp2);
int now = 1, pos1, pos2;
rep(i, 1, q)
{
if (f[c[i].ax][c[i].ay] < c[i].lim || f[c[i].bx][c[i].by] < c[i].lim) { ans[c[i].id] = 0; continue; }
while (now <= cnt && e[now].w >= c[i].lim) { merge(now); now++; }
pos1 = id[c[i].ax][c[i].ay]; pos1 = find(pos1);
pos2 = id[c[i].bx][c[i].by]; pos2 = find(pos2);
if (pos1 == pos2) ans[c[i].id] = 1; else ans[c[i].id] = 0;
}
rep(i, 1, q) printf("%s\n", (ans[i] ? "Yes" : "No"));
return 0;
}