HDU6832 A Very Easy Graph Problem(最小生成树)

Problem Description

An undirected connected graph has n n nodes and m m edges, The i -th edge’s length is 2i, Each node i has a value ai , which is either 0 or 1. You need to calculate:

Σi=1nΣj=1nd(i,j)×[ai=1aj=0]

d(i,j) indicates the shortest distance between i and j . [ ] is the Iverson bracket. ∧ indicates AND. Because the answer may be too large, please output the answer modulo 109+7.

Input

The first line contains one integer T(1≤T≤8),indicating the number of test cases.

The second line contains two ingeters n,m(1≤n105,1≤m2×105).

The third line contains n positive integers a1,a2,...,an(ai=0 or 1) —— the value of the nodes.

The following m lines contain two ingeters u,v(1≤u,vn), and the i-th line represents the i-th undirected edge’s length is 2i, between node u and v.

The sum of n,m is no more than 2×105.

Output

Print a single integer—— the value of the answer modulo 109+7.

Sample Input

1

3 2

0 1 0

3 1

3 2

Sample Output

10

关键就是要注意到边权的特殊性...

题目要求所有白点和黑点最短路的值。
每条边的权值是2i,我们可以发现对于第i条边,21+22+...+2i1<2i,所以如果两个点能通过i1条边到达,那肯定比通过第i条更优,所以我们从1n按顺序建最小生成树。

对于白点和黑点的最短路,我们枚举每条边会被多少种白点和黑点通过,统计两侧的黑白点个数,计算贡献即可。

看到有大佬写的点分治:https://blog.csdn.net/weixin_44282912/article/details/107849300

以及奇奇怪怪的树状数组维护:https://blog.csdn.net/leoxe/article/details/107844387

也是很巧妙的思路。

#include <bits/stdc++.h>
#define N 100005
#define M 200005
#define ll long long
using namespace std;
const ll mod = 1e9+7;
int n, m, tot = 0, tot0, tot1, head[N], ver[2 * M], Next[2 * M], fa[N], a[N];//tot0和tot1为总的0和1的个数 
int zero[N], size[N];//zero[i]表示i为根的子树里0的个数 (包括自己) 1的个数可以用size减出来 
long long ans = 0;
ll edge[2 * M];
void add(int x, int y, ll z)
{
	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}
int get(int x)
{
	if(x == fa[x]) return x;
	return (fa[x] = get(fa[x]));
}
int dfs0(int x, int pre)
{
	size[x] = 1;
	for(int i = head[x]; i; i = Next[i])
	{
		int y = ver[i];
		if(y == pre) continue;
		size[x] += dfs0(y, x);
	}
	return size[x];
}
int dfs1(int x, int pre)
{
	if(a[x] == 0) zero[x] = 1;
	else zero[x] = 0;
	for(int i = head[x]; i; i = Next[i])
	{
		int y = ver[i];
		if(y == pre) continue;
		zero[x] += dfs1(y, x);
	}
	return zero[x];
}
void dfs(int x, int pre)
{
	for(int i = head[x]; i; i = Next[i])
	{
		int y = ver[i];
		ll z = edge[i];
		if(y == pre) continue;
		int up0 = tot0 - zero[y];
		int up1 = tot1 - (size[y] - zero[y]);
		ans = (ans + z * (zero[y] * up1 % mod) % mod ) % mod;
		ans = (ans +  z * (size[y] - zero[y]) % mod * up0 % mod ) % mod;
		dfs(y, x);
	}
}
signed main()
{
	//freopen("1.in","r",stdin);
	//freopen("my.out","w",stdout);
	int t;
	cin >> t;
	while(t--)
	{
		tot = tot0 = tot1 = 0;
		memset(head, 0, sizeof(head));
		memset(zero, 0, sizeof(zero));
		memset(size, 0, sizeof(size));
	 	ans = 0;
		cin >> n >> m;
		for(int i = 1; i <= n; i++)
		{
			cin >> a[i];
			if(a[i] == 0) tot0++;
			else tot1++; 
			fa[i] = i;
		}
		ll val = 1;
		for(int i = 1; i <= m; i++)
		{
			int x, y;
			cin >> x >> y;
			val = val * 2 % mod;
			int xx = get(x), yy = get(y);
			if(xx == yy) continue;
			fa[xx] = yy;//!!
			add(x, y, val);
			add(y, x, val);
		}
		dfs0(1, 0);
		dfs1(1, 0);
		dfs(1, 0);
		cout << ans << endl;
	}
	return 0;
}
posted @   脂环  阅读(225)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
主题色彩