zoukankan      html  css  js  c++  java
  • [扫描线][差分约束] Jzoj P4238 纪念碑

    Description

    2034年,纪念中学决定修建校庆100周年纪念碑,作为杰出校友的你被找了过来,帮校方确定纪念碑的选址.
    纪念中学的土地可以看作是一个长为n,宽为m的矩形.它由n* m个1*1的正方形组成,其中左下角的正方形的坐标为(1,1),右上角的正方形的坐标为(n, m).其中有一些土地已经被用来修建建筑物,每一幢建筑物都可以看做是一个左下角为(x1,y1),右上角为(x2,y2)的矩形.
    纪念碑可以看作是一个正方形.校方希望你找出一块最大的正方形区域供他们参考.
     

    Input

    每一组数据的第一行包含三个整数n,m和p,分别表示学校的长,宽以及建筑物的数量.
    接下来的p行,每行包含四个整数x1,y1,x2,y2,分别表示每一幢建筑物左下角以及右上角的坐标.

    Output

    输出一个数,表示可能的最大边长.
     

    Sample Input

    13 5 8
    8 4 10 4
    4 3 4 4
    10 2 12 2
    8 2 8 4
    2 4 6 4
    10 3 10 4
    12 3 12 4
    2 2 4 2

    Sample Output

    3
     

    Data Constraint

    对于30%的数据,p<=1000.
    对于70%的数据,p<=30000.
    对于100%的数据,p<=400000,m,n<=1000000.

    题解

    • 题目大意:在一个n*m的区间内,有p个长方形的建筑,求在剩下的地方里求一个最大正方形的边长
    • 这种题,我们可以维护x轴上的两个指针l,r每次将扫到的矩阵,拆成两条线段,运用差分约束的思想,加入线段树中
    • 然后我们就可以用线段树来维护y轴,也就是维护一段最长的为0的区间tree[d].v
    • 答案其实就是在r-l+1和tree[1].v中取最小值
    • 当r-l+1>tree[1].v时:
    • 如果r右移,r-l+1会变大,mx不会变大,所以答案不会变大
    • 如果l右移,r-l+1会变小,mx可能会变大,所以答案可能会变大
    • 当r-l+1<=tree[1].v时:
    • 如果r右移,r-l+1会变大,mx不会变大,所以答案可能会变大
    • 如果l右移,r-l+1会变小,mx可能会变大,所以答案会变小
    • 那么根据上面,r右移时,就把对应标号为+1的线段加入;l右移时就把对应标号为-1的线段加入(这个东西可以用vector存)
    • 现在就来考虑一下如何用线段树来维护区间的最长连续0的长度
    • 那么考虑每次操作就是给一段区间+1,-1,这个可以用tag下传
    • tag一定是非负数,那么就考虑两种情况:
    • ①tag为正数,区间肯定就没有0,直接赋值为0
    • ②tag为0时,若这是叶子,那答案为1,否则答案就必须由下面两个儿子合并上来
    • 所以一个节点记录左边延伸多少,右边延伸多少,整个区间最大答案是多少就好了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <vector>
     4 #define N 1000010
     5 using namespace std;
     6 vector<int> P[N],Q[N];
     7 struct Tree {int l,r,x,y,v;}tree[4*N];
     8 int n,m,p,l,r,ans,x1[N],x2[N],y1[N],y2[N],lazy[4*N];
     9 void build(int d,int l,int r)
    10 {
    11     tree[d].l=l,tree[d].r=r,tree[d].x=tree[d].y=tree[d].v=r-l+1;
    12     if (l==r) return;
    13     int mid=l+r>>1;
    14     build(d*2,l,mid),build(d*2+1,mid+1,r);
    15 }
    16 void Lazy_down(int d)
    17 {
    18     if (lazy[d]) 
    19     {
    20         tree[d].x=tree[d].y=tree[d].v=0;
    21         return;
    22     }
    23     if (tree[d].l==tree[d].r)
    24     {
    25         tree[d].x=tree[d].y=tree[d].v=1;
    26         return;
    27     }
    28     tree[d].x=tree[d*2].x+(tree[d*2].x==tree[d*2].r-tree[d*2].l+1)*tree[d*2+1].x;
    29     tree[d].y=tree[d*2+1].y+(tree[d*2+1].y==tree[d*2+1].r-tree[d*2+1].l+1)*tree[d*2].y;
    30     tree[d].v=max(tree[d*2+1].x+tree[d*2].y,max(tree[d*2].v,tree[d*2+1].v));
    31 }
    32 void change(int d,int l,int r,int L,int R,int k)
    33 {
    34     if (L<=l&&r<=R) { lazy[d]+=k,Lazy_down(d); return; }
    35     int mid=tree[d].l+tree[d].r>>1;
    36     if (L<=mid) change(d*2,l,mid,L,R,k); if (mid<R) change(d*2+1,mid+1,r,L,R,k);
    37     Lazy_down(d);
    38 }
    39 int main()
    40 {
    41     scanf("%d%d%d",&n,&m,&p);
    42     for (int i=1;i<=p;i++) scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]),P[x1[i]].push_back(i),Q[x2[i]].push_back(i);
    43     build(1,1,m),l=1,r=1;
    44     while (r<=n)
    45     {
    46         for (int i=0;i<P[r].size();i++) change(1,1,m,y1[P[r][i]],y2[P[r][i]],1);
    47         ans=max(ans,min(tree[1].v,r-l+1));
    48         while (tree[1].v<r-l+1)
    49         {
    50             for (int i=0;i<Q[l].size();i++) change(1,1,m,y1[Q[l][i]],y2[Q[l][i]],-1);
    51             l++;
    52         }    
    53         r++;
    54     }
    55     printf("%d",ans);
    56 }
  • 相关阅读:
    联合索引和多个单列索引选择
    CentOS6.5 一台服务器同时安装多个Mysql数据库
    一次CentOS的服务器被攻击教训
    java版本的memcache静态化
    mysql存储空间满的处理方式
    MariaDB 10.0 和 MariaDB 10.1 存储过程中 PREPARE FROM EXECUTE 区别
    CentOS6.x 优化脚本
    Mysql 使用 “LOAD DATA INFILE”需要注意的问题
    Mysql 日期类型比较 TIMESTAMPDIFF
    CentOS6.x 源码安装Nginx
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10335948.html
Copyright © 2011-2022 走看看