[扫描线][线段树]JZOJ 4238 纪念碑

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 88 4 10 44 3 4 410 2 12 28 2 8 42 4 6 410 3 10 412 3 12 42 2 4 2

Sample Output

3

Data Constraint

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

分析

一看什么矩阵重叠啊什么的先考虑一下扫描线

然后我们用扫描线+线段树维护

扫描线确定横向距离,线段树确定纵向最大空区间

挺好搞的,线段树三个值,一个是从左往右的最大空区间,另一个从右往左,还有一个最大的

更新一下就行,不需要下传标记,因为扫描线迟早会把它去掉

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
#define lson (x<<1)
#define rson ((x<<1)+1)
const int N=1e6+10;
struct Seg {
    int len;
    int v[3],lz;//left right max
}t[4*N];
struct Interval {
    int y1,y2;
};
vector<Interval> add[N],del[N];
int n,m,p;

void Update(int x) {
    if (t[x].lz) {
        t[x].v[0]=t[x].v[1]=t[x].v[2]=0;return;
    }
    if (t[x].len==1) {
        t[x].v[0]=t[x].v[1]=t[x].v[2]=1;return;
    }
    t[x].v[0]=t[lson].v[0]+(t[lson].v[0]==t[lson].len)*t[rson].v[0];
    t[x].v[1]=t[rson].v[1]+(t[rson].v[1]==t[rson].len)*t[lson].v[1];
    t[x].v[2]=max(t[lson].v[1]+t[rson].v[0],max(t[lson].v[2],t[rson].v[2]));
}

void Build(int x,int l,int r) {
    t[x].len=t[x].v[0]=t[x].v[1]=t[x].v[2]=r-l+1;
    if (l==r) return;
    int mid=l+r>>1;
    Build(lson,l,mid);Build(rson,mid+1,r);
}

void Change(int x,int l,int r,int xl,int xr,int k) {
    if (xl<=l&&r<=xr) {
        t[x].lz+=k;Update(x);return;
    }
    int mid=l+r>>1;
    if (xl<=mid) Change(lson,l,mid,xl,xr,k);
    if (mid<xr) Change(rson,mid+1,r,xl,xr,k);
    Update(x);
}

int main() {
    scanf("%d%d%d",&n,&m,&p);
    for (int i=1,x1,x2,y1,y2;i<=p;i++) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),add[x1].push_back((Interval){y1,y2}),del[x2].push_back((Interval){y1,y2});
    Build(1,1,m);
    int l=1,r=1,ans=0;
    while (r<=n) {
        for (int i=0;i<add[r].size();i++) Change(1,1,m,add[r][i].y1,add[r][i].y2,1);
        ans=max(ans,min(t[1].v[2],r-l+1));
        if (r-l+1>t[1].v[2]) {
            for (int i=0;i<del[l].size();i++) Change(1,1,m,del[l][i].y1,del[l][i].y2,-1);
            l++;
        }
        r++;
    }
    printf("%d\n",ans);
}

原文地址:https://www.cnblogs.com/mastervan/p/10335974.html

时间: 2024-10-30 06:13:38

[扫描线][线段树]JZOJ 4238 纪念碑的相关文章

[扫描线][倍增][dfs序][线段树] Jzoj P6276 树

Description 有一棵n个节点的无根树,给出其中的m对点对<x,y>.问有多少条树上的简单路径<u,v>满足该路径上不存在任何一对给出的点对<x,y>. 这里我们认为路径<u,v>和<v,u>是相同的.并且对于题目中给出的点对<x,y>满足x!=y,对于你要计数的路径<u,v>满足u!=v(即单点不算答案). 题解 我们先把每个点在dfs上入队出队的时间给弄出来 然后可以转换为在平面上的n个矩阵 就可以用扫描线+线

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> #include <algorithm> #define MAXN 110 #define LL ((rt<<1)+1) #define RR ((rt<<1)+2) using namespace std; int n; struct segment{ double l

POJ训练计划1177_Picture(扫描线/线段树+离散)

解题报告 题意: 求矩形周长和. 思路: 左扫上扫,扫过了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Seg { int lx,rx,ly,ry,h,v; friend bool operator < (Seg a,Seg b) { re

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

poj 1151 Atlantis (离散化 + 扫描线 + 线段树)

题目链接题意:给定n个矩形,求面积并,分别给矩形左上角的坐标和右上角的坐标. 分析: 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <cstdlib> 6 #include <algorithm> 7 #define LL __int64 8 #define lson l, mid, 2*rt

HDU3265_Posters(扫描线/线段树)

解题报告 题意: 给定的矩形里面有镂空的矩阵,求矩阵面积并. 思路: 直接把一个图形拆成4个矩形,进行面积并. 扫描线+线段树 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define LL __int64 using namespace std; struct Seg { int lx,rx,h,v; friend bool operator

HDU1377_Counting Squares(扫描线/线段树)

解题报告 题意: 矩形面积并. 思路: 扫描线+线段树 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { int lx,rx,h,v; friend bool operator < (Seg a,Seg b) { return a.h<b.h; } } seg[500000]

HDU1542_Atlantis(扫描线/线段树+离散)

解题报告 题目传送门 题意: 求矩形并面积. 思路: 离散+线段树+扫描线. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { int v; double h,lx,rx; friend bool operator < (Seg a,Seg b) { return a.h<b

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &