ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

在地面上有一个水箱,它的俯视图被划分成了n行m列个方格,相邻两个方格之间有一堵厚度可以忽略不计的墙,水
箱与外界之间有一堵高度无穷大的墙,因此水不可能漏到外面。已知水箱内每个格子的高度都是[0,H]之间的整数
,请统计有多少可能的水位情况。因为答案可能很大,请对10^9+7取模输出。两个情况不同当且仅当存在至少一个
方格的水位在两个情况中不同。

Input

第一行包含三个正整数n,m,H(n*m<=500000,1<=H<=10^9)。
接下来n行,每行m-1个整数a[i][j](1<=a[i][j]<=H),表示(i,j)和(i,j+1)之间的墙的高度。
接下来n-1行,每行m个整数b[i][j](1<=b[i][j]<=H),表示(i,j)和(i+1,j)之间的墙的高度。

Output

输出一行一个整数,即方案数模10^9+7的结果。
格子作为点,墙作为边,kruskal求最小生成树,维护每个连通块的水位不溢出的方案数
#include<bits/stdc++.h>
typedef long long i64;
const int N=5e5+77,P=1e9+7;
char ib[N*25],*ip=ib;
int _(){int x;scanf("%d",&x);return x;}
int n,m,h,ep=0;
struct edge{
    int a,b,c;
}e[N*2],eb[N*2];
struct node{
    int f,sz,mx,s;
    int operator[](int c){return c-mx+s;}
}f[N];
void rsort(edge*a,edge*b,int n){
    for(int d=0;d<30;d+=10){
        edge*p=b,*rs[1111];
        int ts[1111];
        memset(ts,0,sizeof(ts));
        for(int i=0;i<n;++i)++ts[a[i].c>>d&1023];
        for(int i=0;i<1024;++i)rs[i]=p,p+=ts[i];
        for(int i=0;i<n;++i)*rs[a[i].c>>d&1023]++=a[i];
        std::swap(a,b);
    }
}
int gf(int x){
    while(x!=f[x].f)x=f[x].f=f[f[x].f].f;
    return x;
}
int main(){
    n=_(),m=_(),h=_();
    for(int i=1;i<=n;++i){
        for(int j=1,x=(i-1)*m;j<m;++j)e[ep++]=(edge){x+j,x+j+1,_()};
    }
    for(int i=1;i<n;++i){
        for(int j=1,x=(i-1)*m;j<=m;++j)e[ep++]=(edge){x+j,x+j+m,_()};
    }
    rsort(e,eb,ep);
    for(int i=1;i<=n*m;++i)f[i]=(node){i,1,-1,0};
    for(int i=0;i<ep;++i){
        int a=gf(eb[i].a),b=gf(eb[i].b),c=eb[i].c;
        if(a==b)continue;
        if(f[a].sz<f[b].sz)std::swap(a,b);
        f[b].f=a;
        f[a].s=(i64)f[a][c]*f[b][c]%P;
        f[a].mx=c;
        f[a].sz+=f[b].sz;
    }
    printf("%d\n",f[gf(1)][h]%P);
    return 0;
}

 

posted on 2017-11-28 01:38  nul  阅读(254)  评论(0编辑  收藏  举报