有一个大小为 n × m n\times m n×m的方格,周围是无限高的墙,内侧的墙则有自己的高度,规定水位高的地方的水会流向水位低的地方,求所有水位高度的可能性,答案对 1 0 9 + 7 10^9+7 109+7取模
数据范围: n × m ≤ 5 × 1 0 5 n\times m\leq 5\times 10^5 n×m≤5×105
考虑每道墙依次从矮到高开通(不可能有高的墙先开通,因为在此之前水肯定已经流了)
假设开启了一道墙,这个墙两面的答案分别为 a n s [ x ] , a n s [ y ] ans[x],ans[y] ans[x],ans[y],它们分别处理的是 0 ∼ h [ x ] , 0 ∼ h [ y ] 0\sim h[x],0\sim h[y] 0∼h[x],0∼h[y]的情况
那么如果把这面高度为 e [ i ] . h e[i].h e[i].h墙开通,则左边的方案为 ( a n s [ x ] + e [ i ] . h − h [ x ] ) (ans[x]+e[i].h-h[x]) (ans[x]+e[i].h−h[x]),表示新增了这么多的高度
右边的同理,合并起来即为两数相乘
时间复杂度: O ( n m l o g n m ) O(nmlognm) O(nmlognm)
#include
#include
#include
#define LL long long
#define id(i,j) (i-1)*m+j
#define mod 1000000007
using namespace std;int n,m,tot,f[500010];
struct node{int from,to;LL h;}e[1000010];
inline bool cmp(node x,node y) {return x.h<y.h;}
inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
LL x,H,Ans[500010],h[500010];
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
signed main()
{
n=read();m=read();H=read();
for(register int i=1;i<=n;i++)
for(register int j=1;j<m;j++)
{
x=read();
e[++tot]=(node){id(i,j),id(i,j+1),x};
}
for(register int i=1;i<n;i++)
for(register int j=1;j<=m;j++)
{
x=read();
e[++tot]=(node){id(i,j),id(i+1,j),x};
}
for(register int i=1;i<=n*m;i++) f[i]=i,Ans[i]=1;
sort(e+1,e+1+tot,cmp);
for(register int i=1;i<=tot;i++)
{
int fx=find(e[i].from),fy=find(e[i].to);
if(fx==fy) continue;
f[fy]=fx;
Ans[fx]=(Ans[fx]+e[i].h-h[fx])*(Ans[fy]+e[i].h-h[fy])%mod;
h[fx]=e[i].h;
}
int fx=find(1);
printf("%lld",(Ans[fx]+H-h[fx]+mod)%mod);
}