【算法分析】
- 显然同样大小的子矩阵中,符合条件的最多一个
- 考虑判断 [ 0... i − 1 ] [0...i-1] [0...i−1]的数是否构成一个矩形:
- 将 [ 0... i − 1 ] [0...i-1] [0...i−1]所在格点染成黑色,剩下的染成白色
- 将边界以外的格点看作白色
- 如果 [ 0... i − 1 ] [0...i-1] [0...i−1]的数是否构成一个矩形,那么这 i i i个点中:
- ( 1 ) (1) (1) “左上都是白点”的黑点数记为 x x x, x = 1 x=1 x=1
- ( 2 ) (2) (2) “上下左右4个点中,是黑点的大于等于2个”的白点记为 y y y, y = 0 y=0 y=0
- 满足 ( 1 ) (1) (1),就满足了这 i i i个点处于同一连通块
- 满足
(
2
)
(2)
(2),就满足了这
i
i
i个点构成一个矩形,不满足则说明存在“拐角”,例如(下图中
B
B
B为满足
(
2
)
(2)
(2)的白点):
W B WB WB
W W WW WW - 如果只满足 ( 2 ) (2) (2),不满足 ( 1 ) (1) (1),可能构成多个矩形
- 因为不存在 x = 0 x=0 x=0且 y = 1 y=1 y=1的情况(实际上是没有 x = 0 x=0 x=0的情况)
- 所以满足 x + y = 1 x+y=1 x+y=1即合法
- 线段树维护对于每个 i i i, x + y x+y x+y的值
- 并且维护区间最小值及最小值个数(最小值不可能为0)
- 对于每个点 u u u,一定是先白后黑
- 记 u u u为白点的最晚时刻为 l [ u ] l[u] l[u],为黑点的最早时刻为 r [ u ] r[u] r[u]
- 记 u u u周围 4 4 4个点的 r r r的次小值为 z z z(如果点越界, r = i n f r=inf r=inf)
- 它作为满足 ( 2 ) (2) (2)的点的时段即 [ z , l [ u ] ] [z,l[u]] [z,l[u]](注意特判 z > l [ u ] z>l[u] z>l[u]的情况)
- 那么在线段树上给 [ z , l [ u ] ] + 1 [z,l[u]]+1 [z,l[u]]+1
- 记 u u u左上的 l l l的最小值为 t t t(如果点越界, l = H W − 1 l=HW-1 l=HW−1)
- 它作为满足 ( 1 ) (1) (1)的点的时段即 [ r [ u ] , t ] [r[u],t] [r[u],t](注意特判 r [ u ] > t r[u]>t r[u]>t的情况)
- 那么在线段树上给 [ r [ u ] , t ] + 1 [r[u],t]+1 [r[u],t]+1
- 每次交换时,见掉两个点 a , b a,b a,b及他们周围 4 4 4个点(共 O ( 10 ) O(10) O(10)个点)在两点交换前的贡献,交换 a , b a,b a,b,加上这些点在两点交换后的贡献
- 注意如果 10 10 10个点中有重复的,不可以重复加减贡献
- 要记录矩阵中每个位置上的数是什么,以及每个数所在位置是什么
【参考程序】注:由于个人习惯,以下程序中编号为 [ 1... H W ] [1...HW] [1...HW]
#include <bits/stdc++.h>
using namespace std;
#define p2 p << 1
#define p3 p << 1 | 1
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
const int e = 1e6 + 5, dx[] = {-1, 0, 1, 0, 0}, dy[] = {0, -1, 0, 1, 0}, inf = 0x3f3f3f3f;
struct point
{
int x, y;
}a[e];
int val[e * 4], cnt[e * 4], n, m, add[e * 4], q, tmp, id[e], pos[e], vis[e], now;
inline void collect(int p)
{
if (val[p2] == val[p3])
{
val[p] = val[p2];
cnt[p] = cnt[p2] + cnt[p3];
}
else if (val[p2] < val[p3])
{
val[p] = val[p2];
cnt[p] = cnt[p2];
}
else
{
val[p] = val[p3];
cnt[p] = cnt[p3];
}
}
inline void pushdown(int p)
{
if (add[p])
{
add[p2] += add[p];
add[p3] += add[p];
val[p2] += add[p];
val[p3] += add[p];
add[p] = 0;
}
}
inline void build(int l, int r, int p)
{
if (l == r)
{
cnt[p] = 1;
return;
}
int mid = l + r >> 1;
build(l, mid, p2);
build(mid + 1, r, p3);
collect(p);
}
inline void update(int l, int r, int s, int t, int v, int p)
{
if (l == s && r == t)
{
val[p] += v;
add[p] += v;
return;
}
pushdown(p);
int mid = l + r >> 1;
if (t <= mid) update(l, mid, s, t, v, p2);
else if (s > mid) update(mid + 1, r, s, t, v, p3);
else
{
update(l, mid, s, mid, v, p2);
update(mid + 1, r, mid + 1, t, v, p3);
}
collect(p);
}
inline void upt(int l, int r, int v)
{
l = max(l, 1);
r = min(r, tmp);
update(1, tmp, l, r, v, 1);
}
inline int get(int x, int y)
{
return (x - 1) * m + y;
}
inline void join(int x, int y, int opt)
{
vis[get(x, y)] = now;
int i, p[4];
for (i = 0; i < 4; i++)
{
int xx = dx[i] + x, yy = dy[i] + y;
if (xx < 1 || yy < 1 || xx > n || yy > m) p[i] = inf;
else p[i] = id[get(xx, yy)];
}
sort(p, p + 4);
int tim = id[get(x, y)] - 1;
if (p[1] <= tim) upt(p[1], tim, opt);
tim++;
for (i = 0; i < 2; i++)
{
int xx = dx[i] + x, yy = dy[i] + y;
if (xx < 1 || yy < 1 || xx > n || yy > m) p[i] = inf;
else p[i] = id[get(xx, yy)] - 1;
}
sort(p, p + 2);
if (tim <= p[0]) upt(tim, p[0], opt);
}
inline void change(int x, int y, int opt)
{
int i;
for (i = 0; i < 5; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx < 1 || yy < 1 || xx > n || yy > m || vis[get(xx, yy)] == now) continue;
join(xx, yy, opt);
}
}
int main()
{
read(n); read(m); read(q);
int i, u, v;
tmp = n * m;
for (i = 1; i <= tmp; i++)
{
read(a[i].x);
a[i].x++;
read(a[i].y);
a[i].y++;
pos[i] = get(a[i].x, a[i].y);
id[get(a[i].x, a[i].y)] = i;
}
build(1, tmp, 1);
for (i = 1; i <= tmp; i++) join(a[i].x, a[i].y, 1);
while (q--)
{
read(u);
read(v);
u++;
v++;
now++;
change(a[u].x, a[u].y, -1);
change(a[v].x, a[v].y, -1);
int idx = u, idy = v, px = pos[idx],
py = pos[idy];
id[px] = idy;
id[py] = idx;
pos[idx] = py;
pos[idy] = px;
now++;
change(a[u].x, a[u].y, 1);
change(a[v].x, a[v].y, 1);
swap(a[u].x, a[v].x);
swap(a[u].y, a[v].y);
printf("%d\n", cnt[1]);
}
return 0;
}