zoukankan      html  css  js  c++  java
  • 【BZOJ5101】[POI2018]Powód 并查集

    【BZOJ5101】[POI2018]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](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的结果。

    Sample Input

    3 2 2
    1
    1
    1
    1 2
    1 1

    Sample Output

    65
    HINT
    要么全部格子水位都是2,要么全部格子水位都在[0,1]之间,共1+2^6=65种情况。

    题解:先将所有边按高度排序,然后从小到大枚举所有边,用并查集维护格子的连通性。在并查集合并的时候统计一下方案数就好。

    具体地,我们用g表示当前连通块的方案数,h表示这个连通块当前的水位高度,设当前水位为now,于是一次合并的贡献就是(g+now-h)*(g'+now-h')。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define _(A,B) ((A-1)*m+B)
    using namespace std;
    typedef long long ll;
    const ll P=1000000007;
    const int maxn=500010;
    int n,m,H,tot;
    ll ans;
    int f[maxn],h[maxn];
    ll g[maxn];
    struct node
    {
    	int x,y,v;
    	node() {}
    	node(int a,int b,int c) {x=a,y=b,v=c;}
    }p[maxn<<1];
    bool cmp(const node &a,const node &b)
    {
    	return a.v<b.v;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int find(int x)
    {
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    int main()
    {
    	n=rd(),m=rd(),H=rd();
    	int i,j,a,b;
    	for(i=1;i<=n;i++)	for(j=1;j<m;j++)	p[++tot]=node(_(i,j),_(i,j+1),rd());
    	for(i=1;i<n;i++)	for(j=1;j<=m;j++)	p[++tot]=node(_(i,j),_(i+1,j),rd());
    	sort(p+1,p+tot+1,cmp);
    	for(i=1;i<=n*m;i++)	f[i]=i,g[i]=1,h[i]=0;
    	for(i=1;i<=tot;i++)
    	{
    		a=p[i].x,b=p[i].y;
    		if(find(a)!=find(b))
    		{
    			g[f[b]]=(g[f[a]]+p[i].v-h[f[a]])*(g[f[b]]+p[i].v-h[f[b]])%P,h[f[b]]=p[i].v,f[f[a]]=f[b];
    		}
    	}
    	printf("%lld",(g[find(1)]+H-h[find(1)])%P);
    	return 0;
    }
  • 相关阅读:
    金融法规
    大型网站架构演化
    用一张决策图来重新思考你的网站
    互联网产品的一般商业模式
    怎样开始冥想
    创造安宁舒适工作日的17个办法
    人生规划和GTD——"知"、"得"与"合"
    立即行动的七个方法
    文件归档的学问
    入门GTD时间管理系统必读
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7944061.html
Copyright © 2011-2022 走看看