zoukankan      html  css  js  c++  java
  • [整体二分][二维RMQ] Codeforces 1301E Nanosoft

    题目大意

    给定一个(N imes M(1 leq N,M leq 500))的网格,每个格子的颜色为红黄蓝绿之一。(Nanosoft)徽标是一个正方形,且恰好被分成4个大小相等的正方形,左上角的颜色是红色,右上角的颜色是绿色,左下角的颜色是黄色,右下角的颜色是蓝色,如:

    这些是(Nanosoft)徽标,

    这些不是(Nanosoft)徽标

    现在有(Q(1 leq Q leq 3 imes 10^5))个询问,每次询问一个子矩形中最大的(Nanosoft)徽标的面积。

    Sample Input

    5 5 5
    RRGGB
    RRGGY
    YYBBG
    YYBBR
    RBBRG
    1 1 5 5
    2 2 5 5
    2 2 3 3
    1 1 3 5
    4 4 5 5
    

    Sample Output

    16
    4
    4
    4
    0
    

    样例解释

    题解

    容易发现,答案具有单调性。如果子矩形中存在一个较大的(Nanosoft)徽标,那么一定存在比它小的(Nanosoft)徽标。
    不妨以红色方块的右下角为(Nanosoft)徽标的基准点,我们可以(O(NM))预处理出以每一个点为基准点的(Nanosoft)徽标的最大边长。然后对于所有询问去整体二分,假设当前二分到的(Nanosoft)徽标的半边长为(a),询问的子矩形为((x_1,y_1,x_2,y_2)),则若基准点在((x_1+a,y_1+a,x_2-a-1,y_2-a-1))这个子矩形内的(Nanosoft)徽标的最大边长大于等于(a+1),则该询问的答案大于等于(a+1),否则该询问的答案小于等于(a)
    对于子矩形内的最大值,用二维RMQ去处理。
    时间复杂度(Oleft(NM+NM l o gNlogM+Qlogleft(frac{minleft(N,M ight)}{2} ight) ight))

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    #define RG register int
    #define LL long long
    const int inf=1e9;
    
    template<typename elemType>
    inline void Read(elemType &T){
        elemType X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        T=(w?-X:X);
    }
    
    struct Que{int X1,Y1,X2,Y2,ID;};
    Que QUE[300010],Q1[300010],Q2[300010];
    int Mat[502][502][4];
    int LSum[502][502][4],RSum[502][502][4],USum[502][502][4],DSum[502][502][4];
    int RR[502][502],GG[502][502],YY[502][502],BB[502][502],Ex[502][502];
    int Ans[300010];
    int N,M,Q;
    
    inline void Input(){
        Read(N);Read(M);Read(Q);
        char c;
        for(RG i=1;i<=N;++i){
            for(RG j=1;j<=M;++j){
                scanf("%c",&c);
                if(c=='R') Mat[i][j][0]=1;
                else if(c=='G') Mat[i][j][1]=1;
                else if(c=='Y') Mat[i][j][2]=1;
                else if(c=='B') Mat[i][j][3]=1;
            }
            scanf("%c",&c);
        }
        for(RG i=1;i<=Q;++i){
            QUE[i].ID=i;
            Read(QUE[i].X1);Read(QUE[i].Y1);
            Read(QUE[i].X2);Read(QUE[i].Y2);
        }
        if(N==1||M==1){while(Q--) printf("0
    ");}
        return;
    }
    
    inline void Init(){
        for(RG i=1;i<=N;++i){
            for(RG j=1;j<=M;++j){
                for(RG k=0;k<4;++k){
                    if(!Mat[i][j][k]) LSum[i][j][k]=0;
                    else LSum[i][j][k]=LSum[i][j-1][k]+Mat[i][j][k];
                    if(!Mat[i][M-j+1][k]) RSum[i][M-j+1][k]=0;
                    else RSum[i][M-j+1][k]=RSum[i][M-j+2][k]+Mat[i][M-j+1][k];
                    if(!Mat[i][j][k]) USum[i][j][k]=0;
                    else USum[i][j][k]=USum[i-1][j][k]+Mat[i][j][k];
                    if(!Mat[N-i+1][j][k]) DSum[N-i+1][j][k]=0;
                    else DSum[N-i+1][j][k]=DSum[N-i+2][j][k]+Mat[N-i+1][j][k];
                }
            }
        }
        for(RG i=1;i<=N;++i){
            for(RG j=1;j<=M;++j){
                RR[i][j]=min(RR[i-1][j-1]+1,min(LSum[i][j][0],USum[i][j][0]));
                GG[i][M-j+1]=min(GG[i-1][M-j+2]+1,min(RSum[i][M-j+1][1],USum[i][M-j+1][1]));
                YY[N-i+1][j]=min(YY[N-i+2][j-1]+1,min(LSum[N-i+1][j][2],DSum[N-i+1][j][2]));
                BB[N-i+1][M-j+1]=min(BB[N-i+2][M-j+2]+1,min(RSum[N-i+1][M-j+1][3],DSum[N-i+1][M-j+1][3]));
            }
        }
        for(RG i=1;i<=N;++i)
            for(RG j=1;j<=M;++j)
                Ex[i][j]=min(min(RR[i][j],GG[i][j+1]),min(YY[i+1][j],BB[i+1][j+1]));
    }
    
    int maxv[12][12][502][502];
    int pre[502];
    
    void Init_RMQ(){
    	for(RG i=1;i<=N;i++)
            for(RG j=1;j<=M;j++)
                maxv[0][0][i][j]=Ex[i][j];
    	pre[2]=pre[3]=1;
    	for(RG i=4,up=max(N,M);i<=up;i++) pre[i]=pre[i>>1]+1;
    	int up1=pre[N]+1,up2=pre[M]+1;
    	for(RG l1=0;l1<=up1;l1++){
    		for(RG l2=0;l2<=up2;l2++){
    			if(!l1&&!l2) continue;
    			for(RG i=1;(i+(1<<l1)-1)<=N;i++){
    				for(RG j=1;(j+(1<<l2)-1)<=M;j++){
    					if(l2)maxv[l1][l2][i][j]=max(maxv[l1][l2-1][i][j],maxv[l1][l2-1][i][j+(1<<(l2-1))]);
    					else maxv[l1][l2][i][j]=max(maxv[l1-1][l2][i][j],maxv[l1-1][l2][i+(1<<(l1-1))][j]);
    				}
    			}
    		}
    	}
    }
    
    int Query(int x1,int y1,int x2,int y2){
        if(x1>x2 || y1>y2) return 0;
        if(x1==0 || y1==0 || x2==0 || y2==0) return 0;
    	int p=pre[x2-x1+1],q=pre[y2-y1+1];
    	int ans=-inf;
    	ans=max(maxv[p][q][x1][y1],maxv[p][q][x1][y2-(1<<q)+1]);
    	ans=max(ans,max(maxv[p][q][x2-(1<<p)+1][y1],maxv[p][q][x2-(1<<p)+1][y2-(1<<q)+1]));
    	return ans;
    }
    int x1,x2,y1,y2;
    
    void Solve(int L,int R,int x,int y){
    	if(x>y) return;
    	if(L==R){
    		for(register int i=x;i<=y;++i)
    			Ans[QUE[i].ID]=(L<<1)*(L<<1);
    		return;
    	}
    	int mid=(L+R)>>1,cnt1=0,cnt2=0;
    	for(register int i=x;i<=y;++i){
            int temp=Query(QUE[i].X1+(mid+1)-1,QUE[i].Y1+(mid+1)-1,QUE[i].X2-(mid+1),QUE[i].Y2-(mid+1));
            if(temp<mid+1) Q1[++cnt1]=QUE[i];
    		else Q2[++cnt2]=QUE[i];
    	}
    	for(register int i=1;i<=cnt1;++i)
    		QUE[x+i-1]=Q1[i];
    	for(register int i=1;i<=cnt2;++i)
    		QUE[x+cnt1+i-1]=Q2[i];
    	Solve(L,mid,x,x+cnt1-1);
    	Solve(mid+1,R,x+cnt1,y);
    	return;
    }
    
    int main(){
        Input();
        if(N==1||M==1) return 0;
        Init();
        Init_RMQ();
        Solve(0,min(N/2,M/2),1,Q);
        for(RG i=1;i<=Q;++i)
            printf("%d
    ",Ans[i]);
        return 0;
    }
    
    // RG
    // YB
    
  • 相关阅读:
    Leetcode NO.110 Balanced Binary Tree 平衡二叉树
    Leetcode NO.226 Invert Binary Tree 翻转二叉树
    Leetcode NO.215 Kth Largest Element In An Array 数组中的第K个最大元素
    根据特征的浏览器判断
    Cygwin在打开在当前目录
    【转帖】科学对待 健康养猫 打造快乐孕妇
    解决chrome浏览器安装扩展、应用程序一直处在“检查中”的问题
    对【SQL SERVER 分布式事务解决方案】的心得补充
    关于“点击这里继续访问您选择的百度XXX”
    VBA一例:如何保持文本框焦点
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12334736.html
Copyright © 2011-2022 走看看