「CodePlus 2018 3 月賽」尋找車位
阿新 • • 發佈:2019-01-13
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行y列為右下端點的最大正方形大小(不考慮外面的行),然後我們來合併
與
的最大正方形大小,我們只需要考慮過mid這條線的正方形,那麼算這條線左邊的拓展,右邊的拓展,再單調佇列掃一遍可以求出O(m)
顆線段樹的
的答案,然後就合併,嗯合併。
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));
}
}
}