Bounding Wall 线段树 + 思维 ccpc 2020 秦皇岛 B

Bounding Wall 线段树 + 思维

题目大意:

一张n * m 的图,‘#’ 表示干地,‘.' 表示湿地,可以对图有两种操作:

  • 1 x y 表示改变 (x,y) 这个位置的干湿
  • 2 x y 表示查询 (x,y) 作为围墙的一部分的矩形最大面积是多少?

题解:

首先分析复杂度:T = 20,n = 1000,m = 1000,q = 1000, 所以每次操作最大复杂度是 n*log,考虑暴力维护每一个点上下左右最长的连续的干地,每次查询,求以(x,y) 这个点作为上下左右边界的最大值。

建一棵线段树,以(x,y) 这个点作为下边界为例,线段树每一个叶子节点存x这一行的每一个位置往上走的最大值,从 x 位置往上遍历,往上遍历的同时剔除线段树内不满足高度的节点,求每一行的合理区间最左边的1和最右边的1,这个合理区间表示的是遍历到的这一行 i ,位置 (i,y) 的左右区间和 (x,y) 的交集。注意最后判断得到的区间是都包含 y ,只有包含 y 的才是合法更新。

#include <bits/stdc++.h>
#define lson (id<<1)
#define rson (id<<1|1)
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e3+10;
typedef long long ll;
inline int read(){
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}
char s[maxn];
int a[maxn][maxn];
int up[maxn][maxn],down[maxn][maxn];
int Left[maxn][maxn],Right[maxn][maxn];
int mins[maxn<<2],e[maxn];
void push_up(int id){
    mins[id] = min(mins[lson],mins[rson]);
}
void build(int id,int l,int r){
    if(l==r){
        mins[id] = e[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(id);
}
void update(int id,int l,int r,int val){
    if(l==r){
        mins[id] = inf;
        return ;
    }
    int mid = (l+r)>>1;
    if(mins[lson]<=val) update(lson,l,mid,val);
    if(mins[rson]<=val) update(rson,mid+1,r,val);
    push_up(id);
}
int queryL(int id,int l,int r,int x,int y){
    if(r<l) return 2000;
    if(l==r) return l;
    int mid = (l+r)>>1,ans = 2000;
    if(x<=mid&&mins[lson]<inf) ans = queryL(lson,l,mid,x,y);
    if(y>mid&&mins[rson]<inf&&ans==2000) ans = queryL(rson,mid+1,r,x,y);
    return ans;
}
int queryR(int id,int l,int r,int x,int y){
    if(r<l) return -2000;
    if(l==r) return l;
    int mid = (l+r)>>1,ans = -2000;
    if(y>mid&&mins[rson]<inf) ans = queryR(rson,mid+1,r,x,y);
    if(x<=mid&&mins[lson]<inf&&ans==-2000) ans = queryR(lson,l,mid,x,y);
    return ans;
}
int main(){
    int T = read(),cas = 1;
    while(T--){
        int n = read(),m = read(),Q = read();
        for(int i=1;i<=n;i++) {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++){
                if(s[j]=='#') a[i][j] = 1;
                else a[i][j] = 0;
            }
        }
        for(int i=1;i<=m;i++) up[0][i] = down[n+1][i] = 0;
        for(int i=1;i<=n;i++) Left[i][0] = Right[i][m+1] = 0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]) Left[i][j] = Left[i][j-1]+1;
                else Left[i][j] = 0;
            }
            for(int j=m;j>=1;j--){
                if(a[i][j]) Right[i][j] = Right[i][j+1]+1;
                else Right[i][j] = 0;
            }
        }
        for(int j=1;j<=m;j++){
            for(int i=1;i<=n;i++){
                if(a[i][j]) up[i][j] = up[i-1][j] + 1;
                else up[i][j] = 0;
            }
            for(int i=n;i>=1;i--){
                if(a[i][j]) down[i][j] = down[i+1][j] + 1;
                else down[i][j] = 0;
            }
        }
        printf("Case #%d:\n", cas++);
        while(Q--){
            int t = read(),x = read(),y = read();
            if(t==1){
                int pos = x,num = up[x][y];
                if(!a[x][y]) num = -up[pos-1][y]-1;
                up[pos][y] -=num,pos++;
                while(pos<=n&&a[pos][y]) {
                    up[pos][y]-=num;
                    pos++;
                }
                pos = x,num = down[x][y];
                if(!a[x][y]) num = -down[pos+1][y]-1;
                down[pos][y]-=num,pos--;
                while(pos>=1&&a[pos][y]){
                    down[pos][y]-=num;
                    pos--;
                }
                pos = y,num = Left[x][y];
                if(!a[x][y]) num = -Left[x][pos-1]-1;
                Left[x][pos]-=num,pos++;
                while(pos<=m&&a[x][pos]){
                    Left[x][pos]-=num;
                    pos++;
                }
                pos = y,num = Right[x][y];
                if(!a[x][y]) num = -Right[x][pos+1]-1;
                Right[x][pos]-=num,pos--;
                while(pos>=1&&a[x][pos]){
                    Right[x][pos]-=num;
                    pos--;
                }
                a[x][y] ^= 1;
            }
            else{
                if(!a[x][y]){printf("0\n");continue;}
                int L = y-Left[x][y]+1,R = Right[x][y]+y-1,ans = R-L+1;
                for(int i=1;i<=m;i++) e[i] = up[x][i];
                build(1,1,m);
                for(int i=1;i<x;i++){
                    if(!a[x-i][y]) continue;
                    update(1,1,m,i);
                    int el = max(L,y-Left[x-i][y]+1),er = min(R,Right[x-i][y]+y-1);
                    int lc = queryL(1,1,m,el,er),rc = queryR(1,1,m,el,er);
                    if(lc<=y&&y<=rc)ans = max(ans,(i+1)*(rc-lc+1));
                }
                for(int i=1;i<=m;i++) e[i] = down[x][i];
                build(1,1,m);
                for(int i=1;i<=n-x;i++){
                    if(!a[x+i][y]) continue;
                    update(1,1,m,i);
                    int el = max(L,y-Left[x+i][y]+1),er = min(R,Right[x+i][y]+y-1);
                    int lc = queryL(1,1,m,el,er),rc = queryR(1,1,m,el,er);
                    if(lc<=y&&y<=rc)ans = max(ans,(i+1)*(rc-lc+1));
                }
                int U = x - up[x][y] + 1,D = y + down[x][y] - 1;
                ans = max(ans,D - U + 1);
                for(int i=1;i<=n;i++) e[i] = Left[i][y];
                build(1,1,n);
                for(int i=1;i<y;i++){
                    if(!a[x][y-i]) continue;
                    update(1,1,n,i);
                    int eu = max(U,x - up[x][y - i] + 1),ed = min(D,down[x][y-i] + x - 1);
                    int lc = queryL(1,1,n,eu,ed),rc = queryR(1,1,n,eu,ed);
                    if(lc<=x&&x<=rc)ans = max(ans,(i+1)*(rc-lc+1));
                }
                for(int i=1;i<=n;i++) e[i] = Right[i][y];
                build(1,1,n);
                for(int i=1;i<=m-y;i++){
                    if(!a[x][y+i]) continue;
                    update(1,1,n,i);
                    int eu = max(U,x - up[x][y + i] + 1),ed = min(D,down[x][y+i] + x - 1);
                    int lc = queryL(1,1,n,eu,ed),rc = queryR(1,1,n,eu,ed);
                    if(lc<=x&&x<=rc)ans = max(ans,(i+1)*(rc-lc+1));
                }
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}
/*
10
4 3 3
###
#.#
#.#
###
2 3 2
1 3 2
2 3 2
*/
posted @ 2020-10-23 09:52  EchoZQN  阅读(260)  评论(1编辑  收藏  举报