zoukankan      html  css  js  c++  java
  • loj #6302. 「CodePlus 2018 3 月赛」寻找车位【线段树+单调队列】

    考虑静态怎么做:枚举右边界,然后枚举上边界,对应的下边界一定单调不降,单调栈维护每一列从当前枚举的右边界向左最长空位的长度,这样是O(nm)的
    注意到n>=m,所以m<=2000,可以枚举右边界,然后考虑怎么快速知道当前枚举的右边界向左最长空位的长度
    用线段树维护行,每个节点都维护一段连续的列,p[ro][i]表示当i列从ro的区间最上面开始有多少行是全空的,q[ro][i]表示从下,v[ro][i]表示i列向左扩展最大的最大全空正方形的边长,大概是下面这种感觉:

    然后p和q合并的时候类似HOTEL那题,看看左右儿子是否全空来决定直接继承还是加上另一段(因为不涉及其他列所以比较好写)
    然后合并l行到r行的v的时候用单调递增的单调队列,分别维护左儿子的q和右儿子的p,从左到右扫,维护当前[l,r]里的最大正方形
    询问的时候是按顺序把查询区间里的值都合并到一起,注意是按顺序!

    #include<iostream>
    #include<cstdio> 
    using namespace std;
    const int N=4000005;
    int n,m,Q,len[N<<2],ql[N],qr[N],ll,lr,rl,rr;
    struct qwe
    {
    	int f[N<<2];
    	int* operator [](int x)
    	{
    		return f+x*m;
    	}
    }a,p,q,v;
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void ud(int ro,int ls,int rs)
    {
    	ll=rl=1,lr=rr=0;
    	for(int i=1,j=1;i<=m;i++)
    	{
    		while(rl<=rr&&q[ls][qr[rr]]>q[ls][i])
    			rr--;
    		qr[++rr]=i;
    		while(ll<=lr&&p[rs][ql[lr]]>p[rs][i])
    			lr--;
    		ql[++lr]=i;
    		while(ll<=lr&&rl<=rr&&q[ls][qr[rl]]+p[rs][ql[ll]]<i-j+1)
    		{
    			if(qr[rl]<=j)
    				rl++;
    			if(ql[ll]<=j)
    				ll++;
    			j++;
    		}
    		v[ro][i]=max(i-j+1,max(v[ls][i],v[rs][i]));
    	}
    	for(int i=1;i<=m;i++)
    		p[ro][i]=(p[ls][i]==len[ls])?len[ls]+p[rs][i]:p[ls][i];
    	for(int i=1;i<=m;i++)
    		q[ro][i]=(q[rs][i]==len[rs])?len[rs]+q[ls][i]:q[rs][i];
    }
    void build(int ro,int l,int r)
    {
    	len[ro]=r-l+1;
    	if(l==r)
    	{
    		for(int i=1;i<=m;i++)
    			p[ro][i]=q[ro][i]=v[ro][i]=a[l][i];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(ro<<1,l,mid);
    	build(ro<<1|1,mid+1,r);
    	ud(ro,ro<<1,ro<<1|1);
    }
    void update(int ro,int l,int r,int x,int y)
    {
    	if(l==r)
    	{
    		p[ro][y]=q[ro][y]=v[ro][y]=a[x][y];
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid)
    		update(ro<<1,l,mid,x,y);
    	else
    		update(ro<<1|1,mid+1,r,x,y);
    	ud(ro,ro<<1,ro<<1|1);
    }
    int hb(int la,int ro,int l,int r)
    {
    	ll=rl=1,lr=rr=0;
    	int nw=0;
    	for(int i=l,j=l;i<=r;i++)
    	{
    		while(rl<=rr&&q[la][qr[rr]]>q[la][i])
    			rr--;
    		qr[++rr]=i;
    		while(ll<=lr&&p[ro][ql[lr]]>p[ro][i])
    			lr--;
    		ql[++lr]=i;
    		while(ll<=lr&&rl<=rr&&q[la][qr[rl]]+p[ro][ql[ll]]<i-j+1)
    		{
    			if(qr[rl]<=j)
    				rl++;
    			if(ql[ll]<=j)
    				ll++;
    			j++;
    		}
    		nw=max(nw,i-j+1);
    	}
    	for(int i=l;i<=r;i++)
    		p[la][i]=(p[la][i]==len[la])?len[la]+p[ro][i]:p[la][i];
    	for(int i=l;i<=r;i++)
    		q[la][i]=(q[ro][i]==len[ro])?len[ro]+q[la][i]:q[ro][i];
    	len[la]+=len[ro];
    	return nw;
    }
    int ques(int ro,int l,int r,int x,int xx,int y,int yy)
    {
    	if(l==x&&r==xx)
    	{
    		int nw=hb(0,ro,y,yy);
    		for(int i=y;i<=yy;i++)
    			nw=max(nw,min(i-y+1,v[ro][i]));
    		return nw;
    	}
    	int mid=(l+r)>>1;
    	if(xx<=mid)
    		return ques(ro<<1,l,mid,x,xx,y,yy);
    	else if(x>mid)
    		return ques(ro<<1|1,mid+1,r,x,xx,y,yy);
    	else
    	{
    		int nw=ques(ro<<1,l,mid,x,mid,y,yy);
    		return max(nw,ques(ro<<1|1,mid+1,r,mid+1,xx,y,yy));//因为要求按从前往后的顺序合并所以不能直接max两个函数,max的时候处理顺序可能会反
    	}
    }
    int main()
    {
    	n=read(),m=read(),Q=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			a[i][j]=read();
    	build(1,1,n);
    	while(Q--)
    	{
    		int o=read();
    		if(o==0)
    		{
    			int x=read(),y=read();
    			a[x][y]^=1;
    			update(1,1,n,x,y);
    		}
    		else
    		{
    			int x=read(),y=read(),xx=read(),yy=read();
    			for(int i=1;i<=m;i++)
    				p[0][i]=q[0][i]=v[0][i]=0;
    			len[0]=0;
    			printf("%d
    ",ques(1,1,n,x,xx,y,yy));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    JSON学习笔记
    Java面试题之对static的理解
    【知了堂学习笔记】java基础知识之继承
    【知了堂学习笔记】多态基本知识
    Final关键字
    子父类构造函数特点
    原来学编程这么简单,如何理解程序的本质(今天听了【遇见狂神说】发布的《从HelloWorld到程序本质的思考》这个视频,有了自己的一些感悟,在这里和大家做一个分享)
    浅谈c3p0连接池和dbutils工具类的使用
    Mysql数据库重要知识点
    Express安装与调试
  • 原文地址:https://www.cnblogs.com/lokiii/p/10422922.html
Copyright © 2011-2022 走看看