Codeforces 1301E-Nanosoft (two-dimensional RMQ + two points)

Title

Give a n ∗ mn*mnm rectangle, each grid has a color. There are 4 colors in total.
A legal cube is composed of color 1 in the upper left quarter, color 2 in the upper right quarter, color 3 in the lower left quarter, and color 4 in the lower right quarter.
QQQ queries, each query sub-matrix(x 1, y 1, x 2, y 2) (x1,y1,x2,y2)(x1,y1,x2,The area of ​​the largest legal cube in y 2 ) . If it does not exist, output 0.
n, m ≤ 500, q ≤ 3 e 5 n,m\le 500, q\le 3e5n,m500,q3 e 5

Problem solving ideas

First, for each point, find the maximum legal cube size that can be obtained by taking this point as the lower right corner of the upper left part of the legal square. Complexity O (nmlog (n)) O(nmlog(n))O ( n m l o g ( n ) )
Then every query, the answer is divided into two. When checking, find whether the maximum value in the corresponding rectangle is greater than or equal to the check value. Use two-dimensional RMQ to go toO (1) O (1)O ( 1 ) query, preprocessing complexityO (nm ∗ log (nm)) O(nm*log(nm))O(nml o g ( n m ) )
Total complexityO (nm ∗ log (nm) + q ∗ log (n)) O(nm*log(nm)+q*log(n))O(nmlog(nm)+qlog(n))

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
using namespace std;
int n, m, Q;
const int maxn = 520;
char s[maxn];
int d[4][maxn][maxn];
int a[maxn][maxn];
bool in(int x, int y){
    
    if(x < 1 || x > n || y < 1 || y > m) return false; return true;}
bool block(int x1, int y1, int x2, int y2, int o){
    
    
    if(!in(x1, y1) || !in(x2, y2)) return false;
    int sum = (x2-x1+1)*(y2-y1+1);
    return sum == d[o][x2][y2]-d[o][x1-1][y2]-d[o][x2][y1-1]+d[o][x1-1][y1-1];
}
bool check(int x, int y, int r){
    
    
    int x1 = x-r+1, y1 = y-r+1, x2, y2;
    if(!block(x1, y1, x, y, 0)) return false;
    y1 += r; y2 = y+r; x2 = x;
    if(!block(x1, y1, x2, y2, 1)) return false;
    x1 += r; x2 += r;
    if(!block(x1, y1, x2, y2, 3)) return false;
    y1 -= r; y2 -= r;
    if(!block(x1, y1, x2, y2, 2)) return false;
    return true;
}
int lg2[maxn];
int dp[9][9][maxn][maxn];
int get_max(int x1, int y1, int x2, int y2){
    
    
    int k = lg2[x2-x1+1], l = lg2[y2-y1+1];
    int t1 = max(dp[k][l][x1][y1], dp[k][l][x2-(1<<k)+1][y1]);
    int t2 = max(dp[k][l][x1][y2-(1<<l)+1], dp[k][l][x2-(1<<k)+1][y2-(1<<l)+1]);
    return max(t1, t2);
}
bool check(int x1, int y1, int x2, int y2, int lim){
    
    
    if(x1 > x2 || y1 > y2) return false;
    return get_max(x1, y1, x2, y2) >= lim;
}
int main()
{
    
    
    lg2[0] = -1;
    fors(i, 1, maxn) lg2[i] = lg2[i>>1]+1;
    cin>>n>>m>>Q;
    fors(i, 1, n+1) {
    
    
        scanf("%s", s+1);
        fors(j , 1, m+1)
            if(s[j] == 'G') d[1][i][j] = 1;
            else if(s[j] == 'Y') d[2][i][j] = 1;
            else if(s[j] == 'R') d[0][i][j] = 1;
            else if(s[j] == 'B') d[3][i][j] = 1;
    }
    fors(o, 0, 4)
        fors(i, 1, n+1)
            fors(j, 1, m+1)
                d[o][i][j] += d[o][i][j-1]+d[o][i-1][j]-d[o][i-1][j-1];
    fors(i, 1, n+1) fors(j, 1, m+1){
    
    
        int l = 1, r = n;
        while(l <= r){
    
    
            if(check(i, j, mid)) a[i][j] = mid, l = mid+1;
            else r = mid-1;
        }
    }
    fors(k, 0, 9)
    fors(l, 0, 9)
    fors(i, 1, n+1)
    fors(j, 1, m+1){
    
    
            if(k == 0 && l == 0) {
    
    dp[k][l][i][j] = a[i][j]; continue;}
            else if(l == 0) {
    
    
                if(i+(1<<(k-1)) <= n)
                    dp[k][l][i][j] = max(dp[k-1][l][i][j], dp[k-1][l][i+(1<<(k-1))][j]);
                else dp[k][l][i][j] = dp[k-1][l][i][j];
            }
            else {
    
    
                if(j+(1<<(l-1)) <= m)
                    dp[k][l][i][j] = max(dp[k][l-1][i][j], dp[k][l-1][i][j+(1<<(l-1))]);
                else dp[k][l][i][j] = dp[k][l-1][i][j];
            }
        }
    while(Q--){
    
    
        int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int l = 1, r = n;
        int ans = 0;
        while(l <= r){
    
    
            if(check(x1+mid-1, y1+mid-1, x2-mid, y2-mid, mid)) ans = mid, l = mid+1;
            else r = mid-1;
        }
        printf("%d\n", 4*ans*ans);
    }
}

Guess you like

Origin blog.csdn.net/qq_43202683/article/details/104319057