HDU 6832 A Very Easy Graph Problem (最小生成树+dfs)

题意:在这里插入图片描述
题解:最小生成树+dfs
晚输入的边权比之前输入的边权和还要大,根据输入用kruskal求mst。

最短我们已经保证了,既然要求所有1到0的路径和,可以通过dfs求出每条边之后有多少个0和1,用dp数组记录,总的减去之后的就是之前的,根据乘法原理算一下即可。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
int t, n, m, a[maxn], u, v, f[maxn], dp[maxn][2], n0, n1;
ll ans;
vector<pair<int, int> > g[maxn];
void dfs(int u, int pre) {
    
    
	dp[u][a[u]]++;
	for (auto i : g[u]) {
    
    
		if (i.first == pre) continue;
		dfs(i.first, u);
		dp[u][0] += dp[i.first][0];
		dp[u][1] += dp[i.first][1];
	}
	for (auto i : g[u]) {
    
    
		if (i.first == pre) continue;
		ans = (ans + 1ll * dp[i.first][0] * (n1 - dp[i.first][1]) % mod * i.second % mod) % mod;
		ans = (ans + 1ll * dp[i.first][1] * (n0 - dp[i.first][0]) % mod * i.second % mod) % mod;
	}
}
int Find(int x) {
    
    
	return x == f[x] ? x : f[x] = Find(f[x]);
}
int main() {
    
    
	scanf("%d", &t);
	while (t--) {
    
    
		ans = n0 = n1 = 0;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++) {
    
    
			scanf("%d", &a[i]);
			if (a[i]) n1++;
			else n0++;
		}
		for (int i = 1; i <= n; i++) g[i].clear(), dp[i][0] = dp[i][1] = 0, f[i] = i;
		int x = 1;
		for (int i = 1; i <= m; i++) {
    
    
			scanf("%d%d", &u, &v);
			int pu = Find(u);
			int pv = Find(v);
			if (pu == pv) continue;
			f[pu] = pv;
			x = 1ll * x * 2 % mod;
			g[u].push_back(make_pair(v, x));
			g[v].push_back(make_pair(u, x));
		}
		dfs(1, -1);
		printf("%lld\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/107857363