【JZOJ4238】纪念碑

本文介绍了一种使用线段树和扫描线算法解决纪念中学校庆纪念碑选址问题的方法。通过将矩形拆分为一系列操作,利用线段树记录最大空闲长度,实现了高效的正方形区域查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

description

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


analysis

  • 听说是很套路的线段树+++扫描线

  • 主要还是把矩形拆成x1x1x1的插入操作和x2+1x2+1x2+1的删除操作

  • 把操作按xxx排序,用两个指针l,rl,rl,r扫区间,用线段树最大空长度

  • r−l+1r-l+1rl+1大于最大空长度就右移lll,否则右移rrr


code

  • 其实我还是不怎么会扫描线……

  • 这个标是我对着标打的以后我学了扫描线就把这个小坑填了 (FLAG)

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 1000005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll n,m,p,tot,ans;

struct node
{
	ll x,y1,y2,z;
}a[MAXN<<1];

struct point
{
	ll l,r,c,mx;
}tr[MAXN<<2];

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 inline ll max(ll x,ll y)
{
	return x>y?x:y;
}
O3 inline ll min(ll x,ll y)
{
	return x<y?x:y;
}
O3 inline bool cmp(node a,node b)
{
	return a.x<b.x;
}
O3 inline void update(ll t,ll l,ll r)
{
	ll mid=(l+r)>>1;
	tr[t].l=tr[t<<1].l,tr[t].r=tr[t<<1|1].r;
	if (tr[t<<1].l==mid-l+1)tr[t].l+=tr[t<<1|1].l;
	if (tr[t<<1|1].r==r-mid)tr[t].r+=tr[t<<1].r;
	tr[t].mx=max(tr[t<<1].mx,tr[t<<1|1].mx);
	tr[t].mx=max(tr[t].mx,tr[t<<1].r+tr[t<<1|1].l);
}
O3 inline void maketree(ll t,ll l,ll r)
{
	tr[t].mx=tr[t].l=tr[t].r=r-l+1;
	if (l==r)return;
	ll mid=(l+r)>>1;
	maketree(t<<1,l,mid),maketree(t<<1|1,mid+1,r);
}
O3 inline void change(ll t,ll l,ll r,ll x,ll y,ll z)
{
	if (l==x && y==r)
	{
		tr[t].c+=z;
		if (tr[t].c==0)
		{
			if (l==r)tr[t].mx=tr[t].l=tr[t].r=1;
			else update(t,l,r);
		}
		else tr[t].mx=tr[t].l=tr[t].r=0;
		return;
	}
	ll mid=(l+r)>>1;
	if (y<=mid)change(t<<1,l,mid,x,y,z);
	else if (x>mid)change(t<<1|1,mid+1,r,x,y,z);
	else change(t<<1,l,mid,x,mid,z),change(t<<1|1,mid+1,r,mid+1,y,z);
	if (tr[t].c==0)update(t,l,r);
	else tr[t].mx=tr[t].l=tr[t].r=0;
}
O3 int main()
{
	//freopen("T1.in","r",stdin);
	n=read(),m=read(),p=read();
	fo(i,1,p)
	{
		ll x1=read(),y1=read(),x2=read(),y2=read();
		a[++tot].x=x1,a[tot].y1=y1,a[tot].y2=y2,a[tot].z=1;
		a[++tot].x=x2+1,a[tot].y1=y1,a[tot].y2=y2,a[tot].z=-1;
	}
	sort(a+1,a+tot+1,cmp);
	maketree(1,1,m);
	ll l=1,r=1,nl=1,nr=1;
	while (a[nl].x==l)
	{
		if (a[nl].z==-1)change(1,1,m,a[nl].y1,a[nl].y2,a[nl].z);
		++nl;
	}
	while (a[nr].x==r)
	{
		if (a[nr].z==1)change(1,1,m,a[nr].y1,a[nr].y2,a[nr].z);
		++nr;
	}
	while (r<=n)
	{
		ans=max(ans,min(tr[1].mx,r-l+1));
		if (r-l+1<=tr[1].mx)
		{
			++r;
			while (a[nr].x==r)
			{
				if (a[nr].z==1)change(1,1,m,a[nr].y1,a[nr].y2,a[nr].z);
				++nr;
			}
		}
		else
		{
			++l;
			while (a[nl].x==l)
			{
				if (a[nl].z==-1)change(1,1,m,a[nl].y1,a[nl].y2,a[nl].z);
				++nl;
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值