# 【BZOJ1016】【Luogu P4208】 [JSOI2008]最小生成树计数 最小生成树，矩阵树定理

• 不同的最小生成树，相同权值使用的边数一定相同。

• 不同的最小生成树，将其都去掉同一个权值的所有边，其连通性一致。

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 100 + 5;
const int M = 1000 + 5;
const int Mod = 31011;

struct Len {
int u, v, w;

bool operator < (Len rhs) const {
return w < rhs.w;
}
}l[M];

vector <Len> v;

int n, m, S[N];

int find (int x) {
return S[x] == x ? x : S[x] = find (S[x]);
}

vector <int> val, use, tot;

vector <int> :: iterator it;

void kruskal () {
sort (l + 1, l + 1 + m);
for (int i = 0; i <= n; ++i) S[i] = i;
for (int i = 1; i <= m; ++i) {
int fu = find (l[i].u);
int fv = find (l[i].v);
it = lower_bound (val.begin (), val.end (), l[i].w);
if (it == val.end ()) {
val.push_back (l[i].w);
use.push_back (0);
tot.push_back (1);
} else {
tot[it - val.begin ()]++;
}
if (fu != fv) {
S[fu] = fv;
it = lower_bound (val.begin (), val.end (), l[i].w);
use[it - val.begin ()]++;
v.push_back (l[i]);
}
}
}

int mat[N][N];

int gauss (int n) {
int ret = 1;
for (int i = 1; i <= n; ++i) {
for (int k = i + 1; k <= n; ++k) {
while (mat[k][i]) {
int d = mat[i][i] / mat[k][i];
for (int j = i; j <= n; ++j) {
(((mat[i][j] -= d * mat[k][j]) %= Mod) += Mod) %= Mod;
}
swap (mat[i], mat[k]); ret = -ret;
}
}
(((ret *= mat[i][i]) %= Mod) += Mod) %= Mod;
}
return abs (ret);
}

void add_edge (int u, int v) {
mat[u][u]++;
mat[v][v]++;
mat[u][v]--;
mat[v][u]--;
}

int sep[N];

int solve () {
kruskal ();
if (v.size () < n - 1) return 0;
int ans = 1;
for (int i = 0; i < val.size (); ++i) {
memset (mat, 0, sizeof (mat));
if (use[i] == 0 || tot[i] == use[i]) continue;
for (int j = 0; j <= n; ++j) S[j] = j;
for (int j = 0; j < v.size (); ++j) {
if (v[j].w != val[i]) {
S[find (v[j].u)] = find (v[j].v);
}
}
int cnt = 0;
for (int i = 1; i <= n; ++i) {
sep[++cnt] = find (i);
}
sort (sep + 1, sep + 1 + cnt);
cnt = unique (sep + 1, sep + 1 + cnt) - sep - 1;
for (int j = 1; j <= m; ++j) {
if (l[j].w == val[i]) {
int fu = find (l[j].u);
int fv = find (l[j].v);
fu = lower_bound (sep + 1, sep + 1 + cnt, fu) - sep;
fv = lower_bound (sep + 1, sep + 1 + cnt, fv) - sep;
}
}
(ans *= gauss (use[i])) %= Mod;
}
return ans;
}

signed main () {
//	freopen ("data.in", "r", stdin);
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
static int u, v, w;
cin >> u >> v >> w;
l[i] = (Len) {u, v, w};
}
cout << solve () << endl;
}

posted @ 2019-05-29 20:32  Nativ  阅读(82)  评论(0编辑  收藏