「CodePlus 2018 3 月赛」寻找车位

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/85715132

access_globe 有一个巨大的停车场,这个停车场有 nn 行,每行有 mm 个车位。为了美观,access_globe 在建立这个停车场时,规定这个停车场必须是长条形的,即 n\ge mn≥m。每个车位都是一个正方形的区域。
最近,access_globe 正在为抽不到 Missing Poster 而苦恼,因此他请你帮他维护这个停车场。你需要支持两个个事件:
一辆车停到某一个车位中,或一辆车从某个车位开走
查询一个矩形区域内最大的只包含空车位的正方形区域
如果你能帮 access_globe 高效地解决这个问题,access_globe 一定会好好奖励你的。

具体题面

推荐题解
其实就是(对每一列开一颗)开m颗线段树,第y颗线段树x处的值为以x行y列为右下端点的最大正方形大小,线段树就是维护一下最大值。(推荐结合样例理解)
然后发现第y颗线段树 [ l , r ] [l,r] 的值就是l到r行y列为右下端点的最大正方形大小(不考虑外面的行),然后我们来合并 [ l , m i d ] [l,mid] [ m i d + 1 , r ] [mid+1,r] 的最大正方形大小,我们只需要考虑过mid这条线的正方形,那么算这条线左边的拓展,右边的拓展,再单调队列扫一遍可以求出O(m) 1 m 1到m 颗线段树的 [ l , r ] [l,r] 的答案,然后就合并,嗯合并。
O ( m q log n ) O(mq \log n)
AC Code:

#include<bits/stdc++.h>
#define N 4000006
#define lc now<<1
#define rc now<<1|1
using namespace std;

int n,m,q;
struct arr
{int f[4*N];inline int* operator[](int x){ return f+x*m; }}mp,rL,lL,val;
int ql[2005],qr[2005],hl,tl,hr,tr,len[4*N];

inline void Merge(int r,int r1,int r2)
{	hl=hr=tl=tr=0;
	for(int i=1,d=0;i<=m;i++)
	{	for(;hl<tl&&lL[r1][ql[tl-1]]>lL[r1][i];tl--);
		for(;hr<tr&&rL[r2][qr[tr-1]]>rL[r2][i];tr--);
		ql[tl++]=i,qr[tr++]=i;
		for(;hl<tl&&hr<tr&&lL[r1][ql[hl]]+rL[r2][qr[hr]]<i-d;) 
			d++,(ql[hl]<=d)&&(hl++),(qr[hr]<=d)&&(hr++);
		val[r][i]=max(val[r1][i],max(val[r2][i],i-d));}
	for(int i=1;i<=m;i++) 
		lL[r][i]=lL[r2][i]+(lL[r2][i]==len[r2])*lL[r1][i],rL[r][i]=rL[r1][i]+(rL[r1][i]==len[r1])*rL[r2][i];
	len[r]=len[r1]+len[r2];
}
void Modify(int now,int l,int r,int x,int y)
{	if(l==r){ val[now][y]=lL[now][y]=rL[now][y]=(mp[x][y]^=1); return; }
	int mid=(l+r)>>1;x<=mid?(Modify(lc,l,mid,x,y),0):(Modify(rc,mid+1,r,x,y),0);
	Merge(now,lc,rc);}
void Build(int now,int l,int r)
{	if(l==r){ 
		for(int i=1;i<=m;i++) 
			val[now][i]=rL[now][i]=lL[now][i]=mp[l][i];
		len[now]=1;return;}
	int mid=(l+r)>>1;
	Build(lc,l,mid);
	Build(rc,mid+1,r);
	Merge(now,lc,rc);}
int Query(int now,int l,int r,int a,int b,int c,int d)
{	if(r<a || l>c) return 0;	
	if(l>=a && r<=c)
	{	Merge(0,0,now);int ret = 0;
		for(int i=b;i<=d;i++) ret = max(ret,min(i-b+1,max(val[0][i],val[now][i])));
		return ret;}
	int mid = (l+r)>>1;
	return max(Query(rc,mid+1,r,a,b,c,d),Query(lc,l,mid,a,b,c,d));}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]);
	Build(1,1,n);
	for(int op,a,b,c,d;q--;)
	{
		scanf("%d",&op);
		if(op==0)
		{
			scanf("%d%d",&a,&b);
			Modify(1,1,n,a,b);
		}
		else 
		{
			scanf("%d%d%d%d",&a,&b,&c,&d);
			len[0] = 0;
			for(int i=1;i<=m;i++) rL[0][i]=lL[0][i]=val[0][i]=0;
			printf("%d\n",Query(1,1,n,a,b,c,d));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/85715132