bzoj5101

最小生成树

容易想到按照边权合并

每次相当于计算当前联通块的方案数,依次合并即可

#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;
}
View Code

 

posted @ 2019-09-08 21:54  19992147  阅读(111)  评论(0编辑  收藏  举报