最小生成树
容易想到按照边权合并
每次相当于计算当前联通块的方案数,依次合并即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5, P = 1e9 + 7; struct data { int x, y, w; data() {} data(int _x, int _y, int _w) : x(_x), y(_y), w(_w) {} bool friend operator < (const data &a, const data &b) { return a.w < b.w; } } a[maxn]; int n, m, H, tot; int v[maxn], fa[maxn], last[maxn]; int p(int i, int j) { return (i - 1) * m + j; } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() { scanf("%d%d%d", &n, &m, &H); for(int i = 1; i <= n; ++i) for(int j = 1; j < m; ++j) { int x; scanf("%d", &x); a[++tot] = data(p(i, j), p(i, j + 1), x); } for(int i = 1; i < n; ++i) for(int j = 1; j <= m; ++j) { int x; scanf("%d", &x); a[++tot] = data(p(i, j), p(i + 1, j), x); } sort(a + 1, a + tot + 1); for(int i = 1; i <= n * m; ++i) fa[i] = i; memset(last, -1, sizeof(last)); for(int i = 1; i <= tot; ++i) { int x = a[i].x, y = a[i].y; x = find(x); y = find(y); if(x == y) continue; fa[y] = x; v[x] = 1LL * (v[x] + a[i].w - last[x]) * (v[y] + a[i].w - last[y]) % P; last[x] = a[i].w; // printf("v[%d] = %d last[%d] = %d last[%d] = %d w = %d\n", x, v[x], x, last[x], y, last[y], a[i].w); } int x = find(1); printf("%d", (v[x] + H - last[x]) % P); return 0; }