Jzoj P4238 纪念碑___线段树+扫描线

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/86698425

题目大意:

一个长为 n n ,宽为 m m 的矩形.它由 n m n* m 1 1 1*1 的正方形组成。
左下角的正方形的坐标为 ( 1 , 1 ) (1,1) ,
右上角的正方形的坐标为 ( n , m ) (n, m)
p p 片土地被用来修建建筑,,每一个建筑可以看做是一个左下角为 ( x 1 , y 1 ) (x1,y1) ,右上角为 ( x 2 , y 2 ) (x2,y2) 的矩形。
问能在这个 n m n*m 矩形中的空地(没有建筑覆盖的)上找到的一个最大的正方形的边长是多少。

p < = 400000 , m , n < = 1000000 p<=400000,m,n<=1000000

分析:

x x 升序排列,那么一个矩形就可以通过在 x 1 x1 位置时对 [ y 1 , y 2 ] + 1 [y1,y2]+1 ,在 x 2 x2 位置时对其 1 -1 ,来表示这个矩形的贡献,那么就是扫描线的思想了。
2 2 个指针 l , r l,r ,
表示 x x 轴上 r l + 1 r-l+1 都是存在一个或者多个 y y 使得这段内存在长为 r l + 1 r-l+1 的空地,
这时候我们用线段树维护 [ l , r ] [l,r] 中所有加进来的边,
此时我们只进行 + 1 +1 的操作,暂不考虑 1 -1
这样我们就可以知道一个 y y x [ l , r ] x∈[l,r] 时,是否满足 ( x , y ) (x,y) 都是空地,然后我们考虑这时候
该如何修改指针,如果当前的满足条件的 y y 的最大连续长度为 c c ,则
c < r l + 1 c<r-l+1 时,我们右移指针 l l ,直到 c > = r l + 1 c>=r-l+1 r r 此时是不变的, l l 改变, c c 随之改变
然后此时右移的过程中,将 l l 带来的影响消掉(即进行它身上所有的 1 -1 操作)
然后 A n s w e r Answer 就是这个过程中的 m a x max { m i n ( c , r l + 1 ) min(c,r-l+1) }
然后对于求一段连续的最长的合法 y y
y y 分为合法和不合法,
可以转换成 01 01 串中求最长连续 0 0 的个数,
建一颗线段树,树中每个节点都记录,从左端点往右最多有多少个连续 0 0 ,从右端点往左最多有多少个连续 0 0 ,当前区间最长的连续 0 0 的长度为多少
然后转移就是 s o n son 转移给 f a t h e r father ,挺显然的,自己手画一下就好
然后就可以做到 O ( m l o g 2 m + n l o g 2 m ) O(mlog_2m+nlog_2m)

代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/Gx_Man_VIP/article/details/86698425