uva12130 - Summits

链接

https://vjudge.net/problem/UVA-12130

题解

写这种题的时候思路一定要清晰,因为一点点小错可能就是致命的
把所有的点按照高度递减排序,逐个加入,用并查集维护连通性
只要判断一下当前点所在点集的最大值是否等于这个点的值即可知道这个点是不是summit

代码

#include <bits/stdc++.h>
#define maxn 510
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
ll code[maxn][maxn], h, w, d, tot, height[maxn][maxn];
bool mark[maxn][maxn];
struct position
{
    ll x, y, height;
}pos[maxn*maxn];
bool operator<(position p1, position p2)
{
    return p1.height > p2.height;
}
class UF
{
    public:
    ll f[maxn*maxn], mx[maxn*maxn];
    void init(ll n)
    {
        for(auto i=1;i<=n;i++)f[i]=i;
    }
    ll find(ll x){return x==f[x]?x:f[x]=find(f[x]);}
    void merge(ll x, ll y)
    {
        auto fx(find(x)), fy(find(y));
        mx[fy]=max(mx[fy],mx[fx]);
        f[fx]=fy;
    }
    ll qmax(ll x)
    {
        return mx[find(x)];
    }
}uf;
ll read(ll x=0)
{
    ll c, f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return f*x;
}
void init()
{
    ll i, j;
    h=read(), w=read(), d=read();
    tot=0;
    for(i=1;i<=h;i++)for(j=1;j<=w;j++)
    {
        tot++;
        pos[tot].x=i, pos[tot].y=j, pos[tot].height=read();
        uf.mx[tot]=pos[tot].height;
        height[i][j]=pos[tot].height;
        code[i][j]=tot;
    }
    sort(pos+1,pos+tot+1);
}
bool ok(ll x, ll y)
{
    return x>=1 and x<=h and y>=1 and y<=w;
}
void solve()
{
    ll i, dx[]{1,0,-1,0}, dy[]{0,1,0,-1}, dir, p, ans(0ll);
    uf.init(tot);
    for(p=i=1;i<=tot;i++)
    {
        while(p<=tot and pos[p].height>pos[i].height-d)
        {
            auto x=pos[p].x, y=pos[p].y;
            for(dir=0;dir<4;dir++)
            {
                if(ok(x+dx[dir],y+dy[dir]) and height[x+dx[dir]][y+dy[dir]]>pos[i].height-d)
                {
                    uf.merge(code[x][y],code[x+dx[dir]][y+dy[dir]]);
                }
            }
            p++;
        }
        if(pos[i].height==uf.qmax(code[pos[i].x][pos[i].y]))ans++;
    }
    printf("%lld\n",ans);
}
int main()
{
    auto T=read();
    while(T--)
    {
        init();
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值