1. 程式人生 > >[bzoj5101][並查集]Powódź

[bzoj5101][並查集]Powódź

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,表示(i,j)和(i,j+1)之間的牆的高度。 接下來n-1行,每行m個整數b[i]j

,表示(i,j)和(i+1,j)之間的牆的高度。

Output

輸出一行一個整數,即方案數模10^9+7的結果。

Sample Input

3 2 2

1

1

1

1 2

1 1

Sample Output

65

HINT

要麼全部格子水位都是2,要麼全部格子水位都在[0,1]之間,共1+2^6=65種情況。

題解

把牆按高度排序 設sum[i]表示i這個連通塊在上一次訪問到他的時候的水位及以下的方案數 掃到一堵牆的時候 如果這兩個連通塊沒有連在一起 顯然水位到這堵牆的高度時候他們就會連在一起了 設上一次訪問到這兩個連通塊的水位分別是h1,h2 這堵牆的高度是H 這兩個連通塊並起來的答案就是(

sum[u]+Hh1)(sum[v]+Hh2)(sum[u]+H-h1)*(sum[v]+H-h2) 然後就沒了…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define mod 1000000007
using namespace std;
const int dx[3]={0,0,1};
const int dy[3]={0,1,0};
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
int n,m,H;
struct Nod{int h,x,y,op;}w[1110000];int t1;
bool cmp(Nod n1,Nod n2){return n1.h<n2.h;}
int pt(int x,int y){return (x-1)*m+y;}
int fa[510000],lasth[510000];LL sum[510000];
int findfa(int x){return fa[x]==x?fa[x]:fa[x]=findfa(fa[x]);}
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	n=read();m=read();H=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<m;j++)w[++t1].h=read(),w[t1].x=i,w[t1].y=j,w[t1].op=1;
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++)w[++t1].h=read(),w[t1].x=i,w[t1].y=j,w[t1].op=2;
	sort(w+1,w+1+t1,cmp);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)fa[pt(i,j)]=pt(i,j),sum[pt(i,j)]=1;
	int cnt=n*m,last=t1;
	for(int i=1;i<=t1;i++)
	{
		int u=w[i].x,v=w[i].y;
		int x=w[i].x+dx[w[i].op],y=w[i].y+dy[w[i].op];
		int u1=pt(u,v),u2=pt(x,y);
		int p=findfa(u1),q=findfa(u2);
		if(p!=q)
		{
			LL g1=sum[p],g2=sum[q];
			sum[q]=((w[i].h-lasth[p]+g1)*(w[i].h-lasth[q]+g2)%mod);
			lasth[q]=w[i].h;fa[p]=q;cnt--;
		}
		if(cnt==1){last=i;break;}
	}
	printf("%lld\n",(sum[findfa(pt(1,1))]+H-w[last].h)%mod);
	return 0;
}