• [整体二分][二维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
    
  • 相关阅读:
    2019年Pycharm最新激活码_学生党适用
    Day14_分享昨天看到的一句话
    监督学习算法_k-近邻(kNN)分类算法_源代码
    Python学习需要安装的工具
    Python基础学习资料推荐
    总结一下公司项目使用各种较新的前端技术和 Api 的一些经验。
    由 Session 和 Cookie 的区别说起
    我理解的正确的代码
    回忆我是如何赢得一次踢毽子比赛
    日常的例子说明 throttle 和 debounce 的区别
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12334736.html
Copyright © 2020-2023  润新知