最小生成树,黑白点问题

A Very Easy Graph Problem
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 427 Accepted Submission(s): 153

Problem Description
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:

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

d(i,j) indicates the shortest distance between i and j. [ ] is the Iverson bracket. ∧ indicates 𝙰𝙽𝙳.

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

题解

#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e5+10;

int n,m;ll ans=0;
int zero=0,one=0;
vector<pair<int,ll>>G[maxn];
int dp[maxn][2],col[maxn],f[maxn];

void dfs(int u,int f){//f为上一个点
    dp[u][0]=dp[u][1]=0;//dp中记录记录的是经过每条边的黑白点的个数
    dp[u][col[u]]++;
    for(auto it:G[u]){
        int v=it.first;
        if(v==f)continue;
        dfs(v,u);
        dp[u][0]+=dp[v][0];
        dp[u][1]+=dp[v][1];
    }
    for(auto it:G[u]){
        int v=it.first;
        if(v==f)continue;
        ans=(ans+1ll*dp[v][0]*(one-dp[v][1])%mod*it.second)%mod;
        ans=(ans+1ll*dp[v][1]*(zero-dp[v][0])%mod*it.second)%mod;
    }
}

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

int main(){
    //freopen("./data/1.in","r",stdin);
    int T;cin>>T;
    while(T--){
        ans=0,zero=one=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)dp[i][0]=dp[i][1]=0,G[i].clear();
        for(int i=1;i<=n;i++)scanf("%d",&col[i]),f[i]=i;
        for(int i=1;i<=n;i++){
            if(col[i])one++;
            else zero++;
        }
        ll val=1;
        for(int i=1;i<=m;i++){
            int u,v;scanf("%d%d",&u,&v);
            val=val*2%mod;
            int fu=find(u),fv=find(v);
            if(fu==fv)continue;
            f[fu]=fv;
            G[u].push_back(make_pair(v,val));//存放的是满足最小生成树中的点和边
            G[v].push_back(make_pair(u,val));
        }
        dfs(1,-1);
        printf("%lld\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值