hdu 5739(点双连通)

这里写图片描述

#include <bits/stdc++.h>

#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define LL long long
#define pii pair<int,int>
#define MP make_pair
#define ls i << 1
#define rs ls | 1
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define Pi acos(-1.0)
#define mod 1000000007
#define eps 1e-12
#define inf 0x3f3f3f3f
#define N 400010
#define M 800040

void add(int &x, int y){
    x += y;
    if(x >= mod) x -= mod;
}
int qpow(int x, int k){
    int ret = 1;
    while(k){
        if(k & 1) ret = 1LL * ret * x % mod;
        x = 1LL * x * x % mod;
        k >>= 1;
    }
    return ret;
}
int fst[N], vv[M], nxt[M], e;
int pre[N], iscut[N], bccno[N], dc, bcc_cnt;
int S[M], top, rt[N], cnt[N];
int n, m, w[N];
int sum[N], sum2[N], nfw[N], lab[N];
vector<int> bcc[N];
void init(){
    memset(fst, -1, sizeof fst); e = 0;
    memset(pre, 0, sizeof pre);
    memset(iscut, 0, sizeof iscut);
    memset(bccno, 0, sizeof bccno);
    memset(rt, 0, sizeof rt);
    memset(cnt, 0, sizeof cnt);
    memset(lab, 0, sizeof lab);
    bcc_cnt = 0;
}
void adde(int u, int v){
    vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
}
int dfs(int u, int p){
    int lowu = pre[u] = ++dc;
    int child = 0;
    sum[u] = w[u];
    if(p > 0) rt[u] = rt[p];
    cnt[rt[u]]++;
    for(int i = fst[u]; ~i; i = nxt[i]){
        int v = vv[i];
        if(v == p) continue;
        if(!pre[v]){
            S[++top] = u, S[++top] = v;
            child++;
            int lowv = dfs(v, u);
            sum[u] = 1LL * sum[u] * sum[v] % mod;
            lowu = min(lowv, lowu);
            if(lowv >= pre[u]){
                iscut[u] = 1;
                bcc_cnt++;
                bcc[bcc_cnt].clear();
                while(1){
                    int vv = S[top--], uu = S[top--];
                    if(bccno[uu] != bcc_cnt)
                        bcc[bcc_cnt].push_back(uu), bccno[uu] = bcc_cnt;
                    if(bccno[vv] != bcc_cnt)
                        bcc[bcc_cnt].push_back(vv), bccno[vv] = bcc_cnt;
                    if(uu == u && vv == v)
                        break;
                }
            }
        }
        else if(pre[v] < pre[u]){
            S[++top] = u, S[++top] = v;
            lowu = min(lowu, pre[v]);
        }
    }
    if(p < 0 && child == 1) iscut[u] = 0;
    return lowu;
}

void dfs2(int u, int p){
    pre[u] = 1;
    sum2[u] = 0;
    sum[u] = w[u];
    if(p > 0) rt[u] = rt[p];
    for(int i = fst[u]; ~i; i = nxt[i]){
        int v = vv[i];
        if(v == p) continue;
        dfs2(v, u);
        sum[u] = 1LL * sum[u] * sum[v] % mod;
        add(sum2[u], sum[v]);
    }
    nfw[u] = qpow(sum[u], mod - 2);
}
int main(){
    int cas;
    scanf("%d", &cas);
    while(cas--){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i){
            scanf("%d", &w[i]);
            nfw[i] = qpow(w[i], mod - 2);
        }
        init();
        for(int i = 1; i <= m; ++i){
            int u, v;
            scanf("%d%d", &u, &v);
            adde(u, v);
            adde(v, u);
        }
        int all = 0;
        for(int i = 1; i <= n; ++i){
            if(!pre[i]){
                top = dc = 0;
                rt[i] = i;
                dfs(i, -1);
                add(all, sum[i]);
            }
        }

        int tot = n;
        for(int i = 1; i <= bcc_cnt; ++i){
            ++tot;
            int u = tot;
            w[u] = 1;
            for(int j = 0; j < bcc[i].size(); ++j){
                int v = bcc[i][j];
                if(iscut[v]){
                    if(!lab[v]) lab[v] = ++tot;
                    w[lab[v]] = w[v];
                    adde(u, lab[v]), adde(lab[v], u);
                }
                else
                    w[u] = 1LL * w[u] * w[v] % mod;
            }
        }
        for(int i = n + 1; i <= tot; ++i){
            if(!pre[i]){
                rt[i] = i;
                dfs2(i, -1);
            }
        }
        int ret = 0;
        for(int u = 1; u <= n; ++u){
            int ans;
            if(!iscut[u]){
                int p = rt[u];
                if(cnt[p] == 1) ans = (all - sum[p] + mod) % mod; 
                else
                    ans = ((all - sum[p] + mod) % mod + (1LL * sum[p] * nfw[u] % mod)) % mod;
            }
            else{
                int tu = u;
                int p = rt[u];
                u = lab[u];
                if(rt[u] == u)
                    ans = ((all - sum[p] + mod) % mod + sum2[u]) % mod;
                else{
                    ans = (all - sum[p] + mod) % mod;
                    ans = (ans + 1LL * sum[rt[u]] * nfw[u] % mod) % mod;
                    ans = (ans + sum2[u]) % mod;
                }
                u = tu;
            }
            add(ret, 1LL * ans * u % mod);
        }
        printf("%d\n", ret);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值