题目大意:
一个长为
n
n
n,宽为
m
m
m的矩形.它由
n
∗
m
n* m
n∗m个
1
∗
1
1*1
1∗1的正方形组成。
左下角的正方形的坐标为
(
1
,
1
)
(1,1)
(1,1),
右上角的正方形的坐标为
(
n
,
m
)
(n, m)
(n,m)。
有
p
p
p片土地被用来修建建筑,,每一个建筑可以看做是一个左下角为
(
x
1
,
y
1
)
(x1,y1)
(x1,y1),右上角为
(
x
2
,
y
2
)
(x2,y2)
(x2,y2)的矩形。
问能在这个
n
∗
m
n*m
n∗m矩形中的空地(没有建筑覆盖的)上找到的一个最大的正方形的边长是多少。
p < = 400000 , m , n < = 1000000 p<=400000,m,n<=1000000 p<=400000,m,n<=1000000
分析:
将
x
x
x升序排列,那么一个矩形就可以通过在
x
1
x1
x1位置时对
[
y
1
,
y
2
]
+
1
[y1,y2]+1
[y1,y2]+1,在
x
2
x2
x2位置时对其
−
1
-1
−1,来表示这个矩形的贡献,那么就是扫描线的思想了。
设
2
2
2个指针
l
,
r
l,r
l,r,
表示
x
x
x轴上
r
−
l
+
1
r-l+1
r−l+1都是存在一个或者多个
y
y
y使得这段内存在长为
r
−
l
+
1
r-l+1
r−l+1的空地,
这时候我们用线段树维护
[
l
,
r
]
[l,r]
[l,r]中所有加进来的边,
此时我们只进行
+
1
+1
+1的操作,暂不考虑
−
1
-1
−1,
这样我们就可以知道一个
y
y
y在
x
∈
[
l
,
r
]
x∈[l,r]
x∈[l,r]时,是否满足
(
x
,
y
)
(x,y)
(x,y)都是空地,然后我们考虑这时候
该如何修改指针,如果当前的满足条件的
y
y
y的最大连续长度为
c
c
c,则
c
<
r
−
l
+
1
c<r-l+1
c<r−l+1时,我们右移指针
l
l
l,直到
c
>
=
r
−
l
+
1
c>=r-l+1
c>=r−l+1,
r
r
r此时是不变的,
l
l
l改变,
c
c
c随之改变
然后此时右移的过程中,将
l
l
l带来的影响消掉(即进行它身上所有的
−
1
-1
−1操作)
然后
A
n
s
w
e
r
Answer
Answer就是这个过程中的
m
a
x
max
max{
m
i
n
(
c
,
r
−
l
+
1
)
min(c,r-l+1)
min(c,r−l+1)}
然后对于求一段连续的最长的合法
y
y
y,
y
y
y分为合法和不合法,
可以转换成
01
01
01串中求最长连续
0
0
0的个数,
建一颗线段树,树中每个节点都记录,从左端点往右最多有多少个连续
0
0
0,从右端点往左最多有多少个连续
0
0
0,当前区间最长的连续
0
0
0的长度为多少
然后转移就是
s
o
n
son
son转移给
f
a
t
h
e
r
father
father,挺显然的,自己手画一下就好
然后就可以做到
O
(
m
l
o
g
2
m
+
n
l
o
g
2
m
)
O(mlog_2m+nlog_2m)
O(mlog2m+nlog2m)了
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define lson(x) x * 2
#define rson(x) x * 2 + 1
#define N 1000005
#define M 400005
using namespace std;
typedef long long ll;
struct Code { int maxlen, llen, rlen, lazy; }C[N*4];
struct Node { int x, y1, y2, z; }a[M*2];
int Answer, cnt, n, m, p;
bool cmp(Node aa, Node bb)
{
if (aa.z == bb.z) return aa.x < bb.x;
return aa.z > bb.z;
}
void Addcder(int x, int y1, int y2, int z)
{
a[++cnt].x = x, a[cnt].y1 = y1, a[cnt].y2 = y2, a[cnt].z = z;
}
void update(int x, int l, int r)
{
int mid = (l + r) >> 1;
C[x].llen = C[lson(x)].llen;
C[x].rlen = C[rson(x)].rlen;
if (C[lson(x)].llen == mid - l + 1) C[x].llen += C[rson(x)].llen;
if (C[rson(x)].rlen == r - mid) C[x].rlen += C[lson(x)].rlen;
C[x].maxlen = max(max(C[lson(x)].maxlen, C[rson(x)].maxlen), C[lson(x)].rlen + C[rson(x)].llen);
}
void Build(int x, int l, int r)
{
C[x].maxlen = C[x].llen = C[x].rlen = r - l + 1;
if(l == r) return;
int mid = (l + r) >> 1;
Build(lson(x), l, mid);
Build(rson(x), mid + 1, r);
}
void change(int x, int l, int r, int L, int R, int num)
{
if (L <= l && r <= R)
{
C[x].lazy += num;
if (!C[x].lazy)
{
if (l == r) C[x].maxlen = C[x].llen = C[x].rlen = 1;
else update(x, l, r);
}
else C[x].maxlen = C[x].llen = C[x].rlen = 0;
return;
}
int mid = (l + r) >> 1;
if (L <= mid) change(lson(x), l, mid, L, R, num);
if (R > mid) change(rson(x), mid + 1,r, L, R, num);
if(!C[x].lazy)
{
if (l == r) C[x].maxlen = C[x].llen = C[x].rlen = 1;
else update(x, l, r);
}
else C[x].maxlen = C[x].llen = C[x].rlen = 0;
}
int main()
{
scanf("%d %d %d", &n, &m, &p);
for (int i = 1; i <= p; i++)
{
int x1, y1, x2, y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
Addcder(x1, y1, y2, 1);
Addcder(x2, y1, y2, - 1);
}
sort(a + 1, a + cnt + 1, cmp);
Build(1, 1, m);
int now = 1, cop = p + 1, l = 1, r = 1;
for (; r <= n; r++)
{
while (a[now].x == r && now <= p) change(1, 1, m, a[now].y1, a[now].y2, 1), now++;
Answer = max(Answer, min(C[1].maxlen, r - l + 1));
while (C[1].maxlen < r - l + 1)
{
while (a[cop].x == l && cop <= p * 2) change(1, 1, m, a[cop].y1, a[cop].y2, - 1), cop++;
l++;
}
}
printf("%d\n", Answer);
return 0;
}