gym102769B. Bounding Wall ccpc2020秦皇岛

https://codeforces.com/gym/102769/problem/B

写完到调试到对拍出来前前后后用了6个小时,写这种码农题还是功力不够。。。现场感觉是不可能写出来的,现场也只有pku和渡渡鸟过了这题

思路挺简单的,就枚举这个点在分别的左右上下边界上

大致讲一下在左边界上怎么求最大的矩形

首先l[i][j]表示i能连续最左边到哪,也就是最小的j,r[i][j]为最优边,u[i][j]为最上边也就是最小的x,d[i][j]最下边

然后先求出上边最高可以到哪,由于(x,y)在左边界,我们就去枚举右边界的j,然后首先a[x][j]必须是有的,然后对于他能拓展到的最高的ua[x][j],x最小可以是多少,这个东西可以在树状数组上二分完成,树状数组存长度为下标,前缀和为有多少条a(i,y)可以拓展到j的,也就是需要预处理(x,y)向上走也就是(i<x),y)可以向右拓展的最远距离,先把他们全部加入树状数组中,再把他们加入向右最远距离的消除vector中

然后枚举右边界j增加的时候,先树状数组上二分找到能够到当前j中,且左边界和右边界向上都能够着的区间中,最大长度是多少,然后再看有哪些这里过后就够不到j+1的(i<x,y)向右拓展的长度,吧他们从树状数组中删掉。

这样我们就求出了(x,y)为左边界,且对于每个j能向上最多到多远,然后再求一遍向下最多能到多远,这就求出了左边界的最大矩阵。然后类似地求上下左右就行了

我吐了,应该有简单一点的写法但我不会写,比如四个方向都抽象一下放到一个函数里面,但感觉不会啊 

#include<bits/stdc++.h>
using namespace std;

const int maxl=1010;

int n,m,q,len;
int b[2][maxl],c[2][maxl],bit[2][maxl];
int a[maxl][maxl];
int la[maxl][maxl],ra[maxl][maxl],ua[maxl][maxl],da[maxl][maxl];
char s[maxl];
vector <int> out[2][maxl];

inline void prework()
{
	scanf("%d%d%d",&n,&m,&q);
	len=max(n,m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
			a[i][j]=(s[j]=='#')?1:0;
	}
	for(int i=1;i<=n+1;i++) a[i][m+1]=0;
	for(int i=1;i<=m+1;i++) a[n+1][i]=0;
	for(int i=1;i<=n;i++)
	{	
		for(int j=1;j<=m;j++)
		if(a[i][j]==0)
			la[i][j]=0;
		else if(j-1>0 && a[i][j-1])
			la[i][j]=la[i][j-1];
		else
			la[i][j]=j;
		for(int j=m;j>=1;j--)
		if(a[i][j]==0)
			ra[i][j]=0;
		else if(j+1<=m && a[i][j+1])
			ra[i][j]=ra[i][j+1];
		else
			ra[i][j]=j;
	}
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=n;i++)
		if(a[i][j]==0)
			ua[i][j]=0;
		else if(i-1>0 && a[i-1][j])
			ua[i][j]=ua[i-1][j];
		else
			ua[i][j]=i;
		for(int i=n;i>=1;i--)
		if(a[i][j]==0)
			da[i][j]=0;
		else if(i+1<=n && a[i+1][j])
			da[i][j]=da[i+1][j];
		else
			da[i][j]=i;
	}
}

inline void chg(int x,int y)
{
	if(a[x][y]==1)
	{
		ra[x][y]=(y+1<=m && a[x][y+1])?ra[x][y+1]:y;
		for(int j=y-1;j>=1 && a[x][j];j--)
		if(a[x][j])
			ra[x][j]=ra[x][j+1];
		la[x][y]=(y-1>=1 && a[x][y-1])?la[x][y-1]:y;
		for(int j=y+1;j<=m && a[x][j];j++)
			la[x][j]=la[x][j-1];
		ua[x][y]=(x-1>=1 && a[x-1][y])?ua[x-1][y]:x;
		for(int i=x+1;i<=n && a[i][y];i++)
			ua[i][y]=ua[i-1][y];
		da[x][y]=(x+1<=n && a[x+1][y])?da[x+1][y]:x;
		for(int i=x-1;i>=1 && a[i][y];i--)
			da[i][y]=da[i+1][y];
	}
	else
	{
		ua[x][y]=da[x][y]=la[x][y]=ra[x][y]=0;
		if(y-1>0 && a[x][y-1])
			for(int j=y-1;j>=1 && a[x][j];j--)
				ra[x][j]=y-1;
		if(y+1<=m && a[x][y+1])
			for(int j=y+1;j<=m && a[x][j];j++)
				la[x][j]=y+1;
		if(x+1<=n && a[x+1][y]);
			for(int i=x+1;i<=n && a[i][y];i++)
				ua[i][y]=x+1;
		if(x-1>0 && a[x-1][y])
			for(int i=x-1;i>=1 && a[i][y];i--)
				da[i][y]=x-1;
	}
}

inline void add(int i,int x,int bit[])
{
	while(i<=len)
	{
		bit[i]+=x;
		i+=i&-i;
	}
}
inline int sum(int i,int bit[])
{
	int ret=0;
	while(i)
	{
		ret+=bit[i];
		i-=i&-i;
	}
	return ret;
}
inline int qry(int d,int bit[])
{
	int ret=0,sum=0;
	for(int i=10;i>=0;i--)
	if(ret+(1<<i)<=len && sum+bit[ret+(1<<i)]<d)
		ret+=1<<i,sum+=bit[ret];
	return ret+1;
}

inline void init(int a[2][maxl])
{
	for(int i=1;i<=len;i++)
	{
		bit[0][i]=bit[1][i]=0;
		out[0][i].clear();out[1][i].clear();
		a[0][i]=a[1][i]=0;
	}
}

inline void mainwork()
{
	int op,x,y,l1,l2,ans,d;
	for(int cas=1;cas<=q;cas++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)
		{
			a[x][y]^=1;
			chg(x,y);
		}
		else
		{
			if(!a[x][y])
			{
				puts("0");
				continue;
			}
			ans=1;
			init(b);
			l1=b[0][0]=b[1][0]=x-ua[x][y]+1;//up down left 0/right 1
			for(int i=x;i>=1 && a[i][y];i--)
			{
				if(y-la[i][y]>0)
					add(x-i+1,1,bit[0]),out[0][y-la[i][y]].push_back(x-i+1);	
				if(ra[i][y]-y>0)
					add(x-i+1,1,bit[1]),out[1][ra[i][y]-y].push_back(x-i+1);
			}
			for(int j=y-1;j>=1;j--)
			{
				if(a[x][j])
				{
					l2=x-ua[x][j]+1;
					d=sum(min(l1,l2),bit[0]);
					b[0][y-j]=(d==0)?0:qry(d,bit[0]);
				}
				for(int id:out[0][y-j])
					add(id,-1,bit[0]);
			}
			for(int j=y+1;j<=m;j++)
			{
				if(a[x][j])
				{	
					l2=x-ua[x][j]+1;
					d=sum(min(l1,l2),bit[1]);
					b[1][j-y]=(d==0)?0:qry(d,bit[1]);
				}
				for(int id:out[1][j-y])
					add(id,-1,bit[1]);
			}
			init(c);
			l1=c[0][0]=c[1][0]=da[x][y]-x+1;
			for(int i=x;i<=n && a[i][y];i++)
			{	
				if(y-la[i][y]>0)
					add(i-x+1,1,bit[0]),out[0][y-la[i][y]].push_back(i-x+1);
				if(ra[i][y]-y>0)
					add(i-x+1,1,bit[1]),out[1][ra[i][y]-y].push_back(i-x+1);
			}
			for(int j=y-1;j>=1;j--)
			{
				if(a[x][j])
				{
					l2=da[x][j]-x+1;
					d=sum(min(l1,l2),bit[0]);
					c[0][y-j]=(d==0)?0:qry(d,bit[0]);
				}
				for(int id:out[0][y-j])
					add(id,-1,bit[0]);
			}
			for(int j=y+1;j<=m;j++)
			{
				if(a[x][j])
				{
					l2=da[x][j]-x+1;
					d=sum(min(l1,l2),bit[1]);
					c[1][j-y]=(d==0)?0:qry(d,bit[1]);
				}
				for(int id:out[1][j-y])
					add(id,-1,bit[1]);
			}
			for(int i=0;i<=len;i++)
			{
				if(b[0][i] && c[0][i])
					ans=max(ans,(b[0][i]+c[0][i]-1)*(i+1));
				if(b[1][i] && c[1][i])
					ans=max(ans,(b[1][i]+c[1][i]-1)*(i+1));
			}
			init(b);
			l1=b[0][0]=b[1][0]=y-la[x][y]+1;  // left right up 0/down 1
			for(int j=y;j>=1 && a[x][j];j--)
			{
				if(x-ua[x][j]>0)
					add(y-j+1,1,bit[0]),out[0][x-ua[x][j]].push_back(y-j+1);
				if(da[x][j]-x>0)
					add(y-j+1,1,bit[1]),out[1][da[x][j]-x].push_back(y-j+1);
			}
			for(int i=x-1;i>=1;i--)
			{
				if(a[i][y])
				{
					l2=y-la[i][y]+1;
					d=sum(min(l1,l2),bit[0]);
					b[0][x-i]=(d==0)?0:qry(d,bit[0]);
				}
				for(int id:out[0][x-i])
					add(id,-1,bit[0]);
			}
			for(int i=x+1;i<=n;i++)
			{
				if(a[i][y])
				{
					l2=y-la[i][y]+1;
					d=sum(min(l1,l2),bit[1]);
					b[1][i-x]=(d==0)?0:qry(d,bit[1]);
				}
				for(int id:out[1][i-x])
					add(id,-1,bit[1]);
			}
			init(c);
			l1=c[0][0]=c[1][0]=ra[x][y]-y+1;
			for(int j=y;j<=m && a[x][j];j++)
			{
				if(x-ua[x][j]>0)
					add(j-y+1,1,bit[0]),out[0][x-ua[x][j]].push_back(j-y+1);
				if(da[x][j]-x>0)
					add(j-y+1,1,bit[1]),out[1][da[x][j]-x].push_back(j-y+1);
			}
			for(int i=x-1;i>=1;i--)
			{
				if(a[i][y])
				{
					l2=ra[i][y]-y+1;
					d=sum(min(l1,l2),bit[0]);
					c[0][x-i]=(d==0)?0:qry(d,bit[0]);
				}
				for(int id:out[0][x-i])
					add(id,-1,bit[0]);
			}
			for(int i=x+1;i<=n;i++)
			{
				if(a[i][y])
				{
					l2=ra[i][y]-y+1;
					d=sum(min(l1,l2),bit[1]);
					c[1][i-x]=(d==0)?0:qry(d,bit[1]);
				}
				for(int id:out[1][i-x])
					add(id,-1,bit[1]);
			}
			for(int i=0;i<=len;i++)
			{
				if(b[0][i] && c[0][i])
					ans=max(ans,(b[0][i]+c[0][i]-1)*(i+1));
				if(b[1][i] && c[1][i])
					ans=max(ans,(b[1][i]+c[1][i]-1)*(i+1));
			}
			printf("%d\n",ans);
		}
	}
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		printf("Case #%d:\n",i);
		mainwork();
	}
	return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值