清题笔记hdu 2020多校6 A Very Easy Graph Problem

清题所用题解:
https://blog.csdn.net/qq_43906000/article/details/107870347
An undirected connected graph has n nodes and 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:
∑ni=1∑nj=1d(i,j)×[ai=1∧aj=0]
d(i,j)ndicates 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≤n≤105,1≤m≤2×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,v≤n), 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
思路:
对于第i条边而言,如果它所连接的u,v两点在第i条边之前就已经被连接了,那么根据2^ 1 +2^ 2+……2 ^ (i-1)<2^i,这条边就是可以直接扔掉的,由此构造kruskal生成树,然后用dfs来处理,我们可以计算一下每条边的左右两侧各有多少黑点和白点。
代码:

#include<bits/stdc++.h>
#include<string>
using namespace std;
typedef long long ll;
const int  mod=1e9+7;
const int N=2e5+10;
struct node{
   int u,v,w;
}a[N*2];
struct tree{
   int to,ne,w;
}b[N];
int cnt=0,h[N],color[N];
int color0[N],color1[N],fa[N];
vector<int>edge;
int n,m;
void add(int u,int v,int w){
   b[cnt]=tree{v,h[u],w};
   h[u]=cnt++;
}
void init(){
   cnt=0;
   edge.clear();
   memset(h,-1,sizeof(h));
   for(int i=1;i<=n;i++)fa[i]=i;
   
}
int find(int x){
   if(fa[x]==x)return x;
   else return fa[x]=find(fa[x]);
} 
void kruskal(int m,int n){
   int num=0;
   for(int i=0;i<=m;i++){
   	int fu=find(a[i].u);
   	int fv=find(a[i].v);
   	if(fu==fv)continue;
   	fa[fu]=fv;
   	num++;
   	add(a[i].u,a[i].v,a[i].w);
   	add(a[i].v,a[i].u,a[i].w);
   	edge.push_back(a[i].w);
   	if(num==n-1)break;
   }
}
ll quick(ll a,ll b){
   ll ans=1;
   a=a%mod;
   while(b){
   	if(b&1)ans=ans*a%mod;
   	a=a*a%mod;
   	b>>=1;
   }
   return ans;
}
struct Col
{
   int nbw,nbb;
   Col operator+(const Col &a)const{
   	return Col{nbw+a.nbw,nbb+a.nbb};
   }
};
Col dfs(int x,int fa)
{
   Col cl=Col{0,0};
   for (int i=h[x]; i!=-1; i=b[i].ne){
   	int v=b[i].to;
   //	printf("v=%d,fa=%d\n",v,fa);
   	if (v==fa) continue;
   	Col p=dfs(v,x);
   	cl=cl+p;
   	color0[b[i].w]=p.nbw;
   	color1[b[i].w]=p.nbb;
   //	printf("v=%d,fa=%d,p.nbw=%d,p.nbb=%d\n",v,fa,p.nbw,p.nbb);
   }
   if (color[x]==0) return cl+Col{1,0};
   return cl+Col{0,1};
}
int main()
{
   int t;
   cin>>t;
   init();
   while(t--){	  	
   	cin>>n>>m;
   	init();
   	int black=0,white=0;
   	for(int i=1;i<=n;i++){
   		cin>>color[i];
   		if(color[i]==0)white++;
   		else black++;
   	}
   	for(int i=1;i<=m;i++){
   		int x,y;
   		cin>>x>>y;
   		a[i-1]=node{x,y,i};
   	}
   	kruskal(m-1,n);
   	dfs(1,-1);
   	ll ans=0;
   	for (auto x:edge){
   		int wt=white-color0[x];
   		int bk=black-color1[x];
   		ans=(ans+(wt*color1[x]%mod)*quick(2,x)%mod)%mod;
   		ans=(ans+(bk*color0[x]%mod)*quick(2,x)%mod)%mod;
   	}
   	printf("%lld\n",ans);
   	
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值