【题解】LuoGu5952:[POI2018]水箱

原题传送门
首先发现就是求一下把墙的高度看成边权,那么就求一个最小生成树,一边求,一边更新答案
对于两个连通块,维护 f 祖 先 , h 最 大 高 度 , n u m 总 方 案 数 f祖先,h最大高度,num总方案数 fhnum
现在用 k r u s k a l kruskal kruskal连上一条长度为 l l l的边
新的连通块的方案数是 ( n u m x + l − h x ) ( n u m y + l − h y ) (num_x+l-h_x)(num_y+l-h_y) (numx+lhx)(numy+lhy)

Code:

#include <bits/stdc++.h>
#define maxn 1000010
#define LL long long
using namespace std;
const LL qy = 1000000007;
int n, m, H, tot, f[maxn], h[maxn];
struct Line{
	int x, y, len;
}line[maxn];
LL num[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool cmp(Line x, Line y){ return x.len < y.len; }
int getfa(int k){ return f[k] == k ? k : f[k] = getfa(f[k]); }

int main(){
	n = read(), m = read(), H = read();
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j < m; ++j) line[++tot] = (Line){(i - 1) * m + j, (i - 1) * m + j + 1, read()};
	for (int i = 1; i < n; ++i)
		for (int j = 1; j <= m; ++j) line[++tot] = (Line){(i - 1) * m + j, i * m + j, read()};
	for (int i = 1; i <= n * m; ++i) f[i] = i, num[i] = 1 ;
	sort(line + 1, line + 1 + tot, cmp);
	for (int i = 1; i <= tot; ++i){
		int x = line[i].x, y = line[i].y, s1 = getfa(x), s2 = getfa(y), l = line[i].len;
		if (s1 != s2) num[s1] = (num[s1] + l - h[s1]) * (num[s2] + l - h[s2]) % qy, f[s2] = s1, h[s1] = l;
	}
	printf("%lld\n", (num[getfa(1)] + H - h[getfa(1)]) % qy);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值