zoukankan      html  css  js  c++  java
  • 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:
    ", 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
    ");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
    ", ans);
                }
            }
        }
        return 0;
    }
    /*
    10
    4 3 3
    ###
    #.#
    #.#
    ###
    2 3 2
    1 3 2
    2 3 2
    */
    
  • 相关阅读:
    Tuxedo 介绍
    winform如何不卡界面
    银行基金代销系统调研
    如何在wcf中用net tcp协议进行通讯
    20190710用控制台启动一个wcf服务
    wcf必知必会以及与Webapi的区别
    2019年7月第一周总结-RabbitMQ总结
    RabbitMQ入门学习系列(七) 远程调用RPC
    RabbitMQ入门学习系列(六) Exchange的Topic类型
    RabbitMQ入门学习系列(五) Exchange的Direct类型
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13862447.html
Copyright © 2011-2022 走看看