1 条题解

  • 0
    @ 2025-8-24 21:35:46

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar shanjianyu
    None

    搬运于2025-08-24 21:35:46,当前版本为作者最后更新于2017-10-18 18:26:00,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    本题要求求出和某个格子相连的最小边的最大值的最小值(变得权值可以看作为格子与格子之间高度的绝对值之差),因此我们需要用最小生成树来解决,由于询问可能很多我们需要对答案进行预处理。

    建图:我们可以将每个格子和它周围的格子连边,边权为格子高度绝对值之差,之后我们对整个图跑最小生成树。但是我们需要保证至少走过T个格子,我们用并查集维护联通性,还要维护每个集合里面的顶点数以及每个集合它所询问的点数,如果两个集合合并后它们的点数之和>= T,那么其中一个集合询问的点数就对答案有贡献,即ans+=ask[i],ask[i]表示i集合有多少个询问的点(即里面包含多少个钥匙),之后将两个集合合并。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define LL long long 
    #define Maxn 400005
    #define Maxm 1600005
    
    struct node {
        LL u,v,w;
    }e[2*Maxm];
    
    LL n,m,T,cnt,N,tot,M,ans=0;
    LL fa[Maxn],dot[Maxn],ask[Maxn],rank[Maxn];
    LL a[605][605],b[605][605],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    
    bool comp(const node &k1,const node &k2) {return k1.w<k2.w;}
    LL find(LL x) {
        if(fa[x]==x) return x;
        else return fa[x]=find(fa[x]);
    }
    
    //ask[i]表示i集合询问的点数,dot[i]表示i集合里面的点数 
    int main() {
        scanf("%lld%lld%lld",&n,&m,&T);N=n*m;
        for(int i=1;i<=n*m;i++) fa[i]=i,dot[i]=1;
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%lld",&a[i][j]);
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
            scanf("%lld",&b[i][j]);
            ask[(i-1)*m+j]=b[i][j];
        }
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
            for(int k=0;k<4;k++) {
                int x=i+dx[k],y=j+dy[k];
                if(x>n||x<1||y<1||y>m) continue ;
                e[++M].u=(i-1)*m+j;e[M].v=(x-1)*m+y;
                e[M].w=abs(a[i][j]-a[x][y]);
            } 
        }
        sort(e+1,e+M+1,comp);LL r1,r2;
        for(int i=1;i<=M;i++) {
            r1=find(e[i].u);r2=find(e[i].v);
            if(r1!=r2) {
                if(dot[r1]+dot[r2]>=T) {
                    if(dot[r1]<T) ans+=e[i].w*ask[r1]; 
                    if(dot[r2]<T) ans+=e[i].w*ask[r2];//这两句话统计对答案的贡献    
                }    
                if(rank[r1]<rank[r2]) fa[r1]=r2,dot[r2]+=dot[r1],ask[r2]+=ask[r1];
                else {
                    fa[r2]=r1,dot[r1]+=dot[r2],ask[r1]+=ask[r2];
                    if(rank[r1]==rank[r2]) rank[r1]++;
                }
                tot++;
                if(tot==N-1) break;
            }
        } 
        printf("%lld\n",ans);
        return 0;
    } 
    
    • 1

    信息

    ID
    1260
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者