1. 程式人生 > >[掃描線][線段樹]JZOJ 4238 紀念碑

[掃描線][線段樹]JZOJ 4238 紀念碑

upd del 選址 線段樹 build hide 包含 printf ont

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.

分析

一看什麽矩陣重疊啊什麽的先考慮一下掃描線

然後我們用掃描線+線段樹維護

掃描線確定橫向距離,線段樹確定縱向最大空區間

挺好搞的,線段樹三個值,一個是從左往右的最大空區間,另一個從右往左,還有一個最大的

更新一下就行,不需要下傳標記,因為掃描線遲早會把它去掉

技術分享圖片
#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); }
View Code

[掃描線][線段樹]JZOJ 4238 紀念碑