这道题比赛的时候真的很可惜,就差一点点,当时脑子胡了,边权点权傻傻分不清
题意
有n个点 m条边的无向图,每个点分别是0 或者 1,问所有0到1的点的距离之和是多少,每条边输入的距离就是2^(i-2)(第一行输入n,m,第二行输入n个0or1,接下来输入m行,第i行输入就是2的i-2次)输出mod 1e9+7思路
其实,比赛时候把他直接转换成最小生成树,因为边是按照从小到大排序输入,所以直接用并查集那种方法生成最小生成树。然后计算这个节点的子节点有多少0和1,统计出来。
接着,计算节点和他的子节点这条边做得贡献,(节点0数量 * 子节点1数量+节点1数量 * 子节点0数量)*边权之和就是答案(比赛时候点权搞错了,一直写成边权,答案输出一直不对,直接自闭)
代码块
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
#define mod 1000000007
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e5+10;
struct node{
int next,to;ll w;
node(){}
node(int sx,int sy,ll ww):next(sx),to(sy),w(ww){}
}a[N<<2];
ll sum,dp[N][2],K;
int tot,head[N],n,m,f[N];
int b[N];
void add(int u,int v,ll w){
a[tot].next=head[u];
a[tot].to=v;
a[tot].w=w;
head[u]=tot++;
}
int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
void dfs(int u,int fa){
dp[u][1]=dp[u][0]=0;
dp[u][b[u]]++;
for(int i=head[u];i!=-1;i=a[i].next){
int v=a[i].to;if(v==fa){continue;}
dfs(v,u);
dp[u][1]+=dp[v][1];
dp[u][0]+=dp[v][0];
}
for(int i=head[u];i!=-1;i=a[i].next){
int v=a[i].to;if(v==fa){continue;}
sum+=((dp[v][0]*(K-dp[v][1]))%mod*a[i].w)%mod;sum%=mod;
sum+=((dp[v][1]*(n-K-dp[v][0]))%mod*a[i].w)%mod;sum%=mod;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tot=0;K=0;
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);if(b[i]==1){K++;}
head[i]=-1;f[i]=i;
}
sum=0;
ll zhi=1;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
int uu=F(u),vv=F(v);zhi*=2;zhi%=mod;
if(uu==vv){continue;}
f[uu]=f[vv];
add(u,v,zhi);add(v,u,zhi);
}
dfs(1,0);
printf("%lld
",sum);
}
return 0;
}
/*
10
3 3
1 2 1
2 3 1
1 3 2
*/