2020 China Collegiate Programming Contest Qinhuangdao Site B. Bounding Wall(思维+并查集)

传送门
B. Bounding Wall
time limit per test4.0 s
memory limit per test512 megabytes
inputstandard input
outputstandard output
Alex is a professional computer game player.

These days, Alex is playing a war strategy game. His land is a rectangular grid with n rows by m columns of cells. He wants to build a bounding wall to protect some vital materials.

The bounding wall is a frame of a×b rectangle whose width is 1. It occupies a rows and b columns, and its coverage area is a⋅b. Note that a=1 or b=1 is also allowed. Each cell has a state, wet or dry. It is impossible to build a bounding wall across a wet cell.
在这里插入图片描述

He will also have several queries about building a bounding wall. The only two possible formats about queries are listed as follows.

1 x y : the state of cell (x,y) changes.
2 x y : Alex wants to build a bounding wall across the cell (x,y) such that the coverage area is as large as possible. Answer the maximum coverage area.
Input
The first line of the input gives the number of test cases, T (1≤T≤1000). T test cases follow.

For each test case, the first line contains three integers n,m and Q (1≤n,m,Q≤103), representing his land has n rows and m columns, and he will have Q queries.

Each of the following n lines contains a string si,1si,2⋯si,m (si,j=’#’ or ‘.’), describing the initial state of his land. If sx,y=’#’, the cell (x,y) will be dry, otherwise, it will be wet.

Each of the following Q lines contains three integers ti (1≤ti≤2), xi (1≤xi≤n) and yi (1≤yi≤m), representing a query.

The sum of max{n,m,Q} in all test cases doesn’t exceed 2×104.

Output
For each test case, the output starts with a line containing “Case #x:”, where x is the test case number (starting from 1). For each queries with ti=2, answer the maximum possible coverage area. If it is impossible to build a bounding wall, print 0.

Example
inputCopy
2
2 3 2

##.
2 2 2
2 1 3
4 3 3

#.#
#.#

2 3 2
1 3 2
2 3 2
outputCopy
Case #1:
4
3
Case #2:
0
9

题意

T(T<=103)组数据,每组数据给你n,m,q(1<=n,m,q<=103)接下来给你一个n*m的字符矩阵s,’.‘表示不能放砖,’#‘表示可以放砖。q次查询,每次查询给你id,x,y(1<=id<=2,1<=x<=n,1<=y<=m),若id为1,则s[x][y]的状态翻转(’.‘与’#‘相互转换),若id为2,则查询包含点(x,y)的最大边框的面积,边框(如图所示)上不能有’.’。

思路

是真的难想啊。
①对于每个询问,我们考虑在O(nlogn)(据说姿势不好会被卡,std为常数更小的 nalpha(a))内求出答案。
②我们将字符矩阵分别旋转0,90,180,270度(相应的询问也要进行变化),这样我们只求出(x,y)作为底边框部分(或者任一方向)的答案取最大值即可。
③用l[x][y],r[x][y],u[x][y]分别求出点(x,y)能向左、右、上可延伸的最大长度,下面只讨论(x,y)作为底边框部分的情况。
④我们枚举顶边框的行i,首先对于底边框和顶边框,必须是连续的一段没有’#‘的部分,因此得到第i行和第x行的第y列分别向左、向右延伸的最大长度,相应的取最值(左边取最大,右边取最小),作为初始答案。此时i需要向上移动,每移动一行,这一行就可能会有某些列上有’.’,导致这一列不能作为边框的一边。由于确定了底边框为第x行,我们直接寻找第x行每一列上面第一个’.'出现的行,当i移动过这行的时候,就把这些列标记,然后寻找可以使边框面积最大的合法的列即可。列标记的过程可以用并查集维护,因为是一段连续的区间,维护这段连续的、不能选的列的左右端点即可。
⑤注意初始化
也有树状数组+二分的做法,感兴趣的可以自己到网上寻找资料。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fi first
#define se second
#define pb push_back
using namespace std;
const int maxn=1e3+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int a[maxn],c[maxn];
int ans[maxn],tmp,cnt;
int flag;
char init_s[maxn][maxn],s[maxn][maxn];
bool vis[maxn];
int l[maxn][maxn], r[maxn][maxn], u[maxn][maxn];
int fa[maxn];
int ma[maxn], mi[maxn];
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
int find(int x) { return fa[x] == -1 ? x : fa[x] = find(fa[x]); }
void un(int x,int y){
    int fx = find(x);
    int fy = find(y);
    if(fx==fy)
        return;
    else {
        fa[fx] = fy;//
        ma[fy] = max(ma[fy], ma[fx]);//
        mi[fy] = min(mi[fy], mi[fx]);//
    }
}
struct node{
    int x, y;
    int id;
}init_q[maxn],q[maxn];
vector<int>vc[maxn];
void cal(){
     rep(i,1,n){
        r[i][m + 1] = m + 1;
        rep(j,1,m){
            l[i][j] = (s[i][j] == '.') ? j : l[i][j - 1];
            u[i][j] = (s[i][j] == '.') ? i : u[i - 1][j];
        }
        dep(j,m,1){
            r[i][j] = (s[i][j] == '.') ? j : r[i][j + 1];
        }
    }
    rep(t,1,k){
        int x, y, nl, nr;
        x=q[t].x;
        y=q[t].y;
        if(q[t].id==1){
            s[x][y]=(s[x][y]=='.')?'#':'.';
            rep(i, 1, m) l[x][i] = (s[x][i] == '.') ? i : l[x][i - 1];
            dep(i, m, 1) r[x][i] = (s[x][i] == '.') ? i : r[x][i + 1];
            rep(i, 1, n) u[i][y] = (s[i][y] == '.') ? i : u[i - 1][y];
            continue;
        }
        rep(i, 0, max(n, m) + 1) {
            fa[i] = -1;
            vc[i].clear();
            vis[i] = 0;
        }
        nl = l[x][y] + 1;
        nr = r[x][y] - 1;
        ans[t] = max(ans[t], nr - nl + 1);
        //if(t==2) cout << " debug: " << ans[t] << " "<<nl<<" "<<nr<<" "<<x<<" "<<y<<endl;
        rep(i, nl, nr) vc[u[x][i]].push_back(i);
        dep(i,x-1,1){
            int cl = max(nl, l[i][y] + 1);
            int cr = min(nr, r[i][y] - 1);
            if(y>=cl&&y<=cr){
                if(vis[cl]){
                    cl = max(cl, ma[find(cl)]) + 1;
                }
                if(vis[cr]){
                    cr = min(cr, mi[find(cr)]) - 1;
                }
                if(cl<=y&&y<=cr)
                    ans[t] = max(ans[t], (x - i + 1) * (cr - cl + 1));
            }
            for(auto x : vc[i]){
                vis[x] = 1;
                ma[x] = mi[x] = x;
                if(vis[x-1])
                    un(x - 1, x);
                if(vis[x+1])
                    un(x, x + 1);
            }
        }
    }
}
void solve(){
    read(n);
    read(m);
    read(k);
    rep(i,1,n){
        scanf("%s", init_s[i] + 1);
    }
    rep(i,1,k){
        read(init_q[i].id);
        read(init_q[i].x);
        read(init_q[i].y);
        ans[i] = 0;
    }
    // 0
    rep(i,1,n){
        rep(j, 1, m) s[i][j] = init_s[i][j];
    }
    rep(i,1,k) {
        q[i].id = init_q[i].id;
        q[i].x = init_q[i].x;
        q[i].y = init_q[i].y;
    }
    cal();
    // 90
    rep(i,1,n){
        rep(j, 1, m) s[j][n - i + 1] = init_s[i][j];
    }
    rep(i,1,k) {
        q[i].id = init_q[i].id;
        q[i].x = init_q[i].y;
        q[i].y = n - init_q[i].x + 1;
    }
    swap(n, m);
    cal();
    swap(n, m);
    //180
    rep(i,1,n){
        rep(j, 1, m) s[n - i + 1][m - j + 1] = init_s[i][j];
    }
    rep(i,1,k){
        q[i].id = init_q[i].id;
        q[i].x = n - init_q[i].x + 1;
        q[i].y = m - init_q[i].y + 1;
    }
    cal();
    // 270
    rep(i,1,n){
        rep(j, 1, m) s[m - j + 1][i] = init_s[i][j];
    }
    rep(i,1,k){
        q[i].id = init_q[i].id;
        q[i].x = m - init_q[i].y + 1;
        q[i].y = init_q[i].x;
    }
    swap(n, m);
    cal();
    rep(i,1,k){
        if(init_q[i].id==2)
            printf("%d\n", ans[i]);
    }
}
int main(){
/*
#ifdef ONLINE_JUDGE
#else
    freopen("D:/Temp/in.txt", "r", stdin);
#endif
*/
    // freopen("e://duipai//myout.txt","w",stdout);
    int T=1,cas=1;
    read(T);
    while(T--){
        printf("Case #%d:\n", cas++);
        solve();
    }
    //system("pause");
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值