BZOJ2936降水(并查集)

题目链接
在这里插入图片描述
考虑枚举降雨量,把一开始的每个点的高度记录在一起,然后根据降雨量枚举。
往当前<=H的点施加降水,然后维护会流出去多少水,ans更新。
枚举一个点check四周比它低的点,合并到一起。把溢出的点连向虚拟的0,因此每次合并都是把溢出的路线合并到0以下。

#include <bits/stdc++.h>
using namespace std;
#define N 1010
#define V 1000009
#define int long long
int mx[4]={0,0,1,-1};
int my[4]={1,-1,0,0};
namespace Union_Find{
    int fa[V],siz[V];
    void init(int n){
        fa[0]=siz[0]=0;
        for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
    }
    int find(int x){
        if(fa[x]==x)return x;
        return fa[x]=find(fa[x]);
    }
    void merge(int x,int y){
        int fx=find(x),fy=find(y);
        if(fx==fy)return;
        siz[fy]+=siz[fx];
        fa[fx]=fy;
    }
};
int n,m;
bool vis[N][N];
vector<pair<int,int> > g[V];
bool checkin(int x,int y){
    if(x<1||y<1||x>n||y>m)return 0;
    return 1;
}
int id(int x,int y){
    if(!checkin(x,y))return 0;
    return (x-1)*m+y;
}
int cnt=0,ans=0;
signed main(){
    using namespace Union_Find;
  //  freopen("2936.in","r",stdin);
    scanf("%lld",&n);
    m=n;
    init(n*m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int vl;scanf("%lld",&vl);
            g[vl].push_back(pair<int,int>(i,j));
        }
    int up=n*m;
    for(int v=0;v<=V;v++){//考虑一层一层地加水
        if(siz[find(0)]==up)break;
        for(int j=0;j<g[v].size();j++){
            int x=g[v][j].first,y=g[v][j].second;
            vis[x][y]=1;
            cnt++;
            for(int k=0;k<4;k++){
                int nx=x+mx[k],ny=y+my[k];
                //如果当前点在边界上或者旁边有比它低的点就合并起来
                //在边界上siz[0]++ 说明这个点不可取
                //不在边界上维护可以到达的联通块
                if(!checkin(nx,ny)||vis[nx][ny])merge(id(nx,ny),id(x,y));
            }
        }
        ans+=cnt-siz[find(0)];
    }
    printf("%lld",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值