2194 4.琵琶湖(lakebiwa)——2015安徽初中

本文介绍了一种利用并查集算法解决水面不断下降问题的方法,通过倒叙操作合并不相连的区域,时间复杂度为O(TlogT+nm)。文章详细解释了如何通过相邻块的合并来更新答案值。
摘要由CSDN通过智能技术生成

“ 对于T次讯问,倒叙考察之。 则问题变成了水面不断下降的情况 。这个时候,每一单位时间,会有额外的格子露出水平,并有可能合并原有的不相连的区域。这样的问题可以被描述为 对若干集合进行合并 ,用 并查集 是最高效的处理方案。总的时间复杂度为O(TlogT+nm)。 ”

细节一下 ,可知,倒叙操作时,假如新出现的小方格周围全是海洋,那么它就能提供一个答案值(当成一个小块)。
接着,我们易知, 每次的方格更新最多只会联通它四个方向上的块 ,所以我们 不需要对整个方格整体进行扫描 ,只需要让当前格 与四个方向上块依次进行合并(还没出现的块不合并) 。当发现他们在同一个块上时,不操作。但他们分别属于不同块时,将其合并,并将答案值减一即可。

# include <stdio.h>
# include <algorithm>
using namespace std;
const int dx[]={1,-1,0,0},dy[]={0,0,-1,1};
struct block {
    int x,y,h;
}c[1000100];
int k,q[100100];
int n,m,fa[1000100],b[100100];
bool up[1010][1010];
inline int getf(int x) {
    int r=x;
    while(fa[r]!=r) r=fa[r];
    int i=x,j;
    while(i!=r) {
        j=fa[i];
        fa[i]=r;
        i=j;
    }
    return r;
}
inline int cmp_block(block _x,block _y) {return _x.h>_y.h;}
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j) {
            int id=(i-1)*m+j;
            c[id].x=i,c[id].y=j;
            fa[id]=id;
            scanf("%d",&c[id].h);
        }
    sort(c+1,c+n*m+1,cmp_block);
    scanf("%d",&k);
    for (int i=1;i<=k;++i)
        scanf("%d",&q[i]);
    int now=1,ans=0;
    for (int i=k;i>=1;--i) {
        while(now<=n*m && c[now].h>q[i]) {
            ans++; int nowx=c[now].x,nowy=c[now].y;
            up[nowx][nowy]=1;
            for (int j=0;j<4;++j) {
                int xx=nowx+dx[j],yy=nowy+dy[j];
                if(xx<1||xx>n||yy<1||yy>m|| !up[xx][yy]) continue;
                int id1=(xx-1)*m+yy,id2=(nowx-1)*m+nowy,fid1=getf(id1),fid2=getf(id2);
                if(fid1!=fid2) {
                    fa[fid1]=fid2;
                    ans--;
                }
            }
            now ++;
        }
        b[i]=ans;
    }
    for(int i=1;i<k;++i) printf("%d ",b[i]);
    printf("%d\n",b[k]);
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值