zoukankan      html  css  js  c++  java
  • HDU5739 Fantasia【点双连通分量 割点】

    HDU5739 Fantasia

    题意:

    给出一张(N)个点的无向图(G),每个点都有权值(w_i),要求计算(sum_{i=1}^{N}icdot G_i % 1e9+7)
    其中(G_i)为删掉点(i)之后剩下各连通块内点权乘积之和

    题解:

    显然对于不是割点的点很容易计算出答案
    对于割点,我们需要知道删掉这个点之后产生的新的连通块的点权乘积和
    (tarjan)过程中可以直接处理出各联通子图的点权乘积(除了父节点所在的子图)
    而父节点所在子图的点权乘积可以用整张图的点权乘积去除掉除它以外的点的点权乘积
    具体实现看代码

    view code
    //#pragma GCC optimize("O3")
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    typedef long long int LL;
    const int MAXN = 2e5+7;
    const LL MOD = 1e9+7;
    int n,m,bccid[MAXN],dfn[MAXN],low[MAXN],ID,w[MAXN],bel[MAXN],idx;
    vector<int> G[MAXN],pt[MAXN];
    LL tot,ans,f[MAXN],gw[MAXN],mul[MAXN],subsum[MAXN],submul[MAXN];
    bool iscut[MAXN];
    LL ksm(LL a, LL b){
        LL ret = 1;
        while(b){
            if(b&1) ret = ret * a % MOD;
            b >>= 1;
            a = a * a % MOD;
        }
        return ret;
    }
    LL inv(LL x){ return ksm(x,MOD-2); }
    void init(){
        for(int i = 1; i <= n; i++) G[i].clear();
        memset(dfn+1,0,n<<2);
        memset(bel+1,0,n<<2);
        memset(iscut+1,0,n);
        fill(submul+1,submul+1+n,1);
        fill(subsum+1,subsum+1+n,0);
        ans = tot = ID = idx = 0;
    }
    void tarjan(int u, int par, int id){
        pt[id].push_back(u);
        bel[u] = id;
        dfn[u] = low[u] = ++idx;
        mul[id] = mul[id] * w[u] % MOD;
        int child = 0;
        for(int v : G[u]){
            if(v==par) continue;
            if(!dfn[v]){
                child++;
                LL tmp = mul[ID];
                tarjan(v,u,id);
                low[u] = min(low[u],low[v]);
                if(low[v]>=dfn[u]){
                    if(par) iscut[u] = true;
                    LL sub = mul[ID] * inv(tmp) % MOD;
                    // 由于不确定根节点是否是割点,所以先当作割点来处理
                    subsum[u] = (subsum[u] + sub) % MOD;
                    submul[u] = submul[u] * sub % MOD;
                }
            }
            else low[u] = min(low[u],dfn[v]);
        }
        if(!par and child > 1) iscut[u] = true;
    }
    void solve(){
        scanf("%d %d",&n,&m);
        init();
        for(int i = 1; i <= n; i++) scanf("%d",&w[i]);
        for(int i = 1; i <= m; i++){
            int u, v; scanf("%d %d",&u,&v);
            G[u].push_back(v); G[v].push_back(u);
        }
        for(int i = 1; i <= n; i++) if(!dfn[i]){
            pt[++ID].clear();
            mul[ID] = 1;
            tarjan(i,0,ID);
            tot = (tot + mul[ID]) % MOD;
            for(int x : pt[ID]){
                if(x==i) continue;
                subsum[x] = (subsum[x] + mul[ID] * inv(submul[x]*w[x]%MOD) % MOD) % MOD;
            }
        }
        for(int i = 1; i <= n; i++){
            LL res = 0;
            if(iscut[i]) res = (tot - mul[bel[i]] + subsum[i] + MOD) % MOD;
            else{
                if(pt[bel[i]].size() == 1) res = (tot - w[i] + MOD) % MOD;
                else res = (tot - mul[bel[i]] + mul[bel[i]] * inv(w[i]) % MOD + MOD) % MOD;
            }
            ans = (ans + i * res) % MOD;
        }
        printf("%I64d
    ",ans);
    }
    int main(){
        int tt;
        for(scanf("%d",&tt); tt; tt--) solve();
        return 0;
    }
    
  • 相关阅读:
    1.打开windows中功能的快捷方式
    16-SQLServer强制走索引
    15-资源等待类型sys.dm_os_wait_stats
    14-SQLServer索引碎片
    13-修复数据库,表,索引
    12-SSMS图形化工具中不允许保存修改的解决办法
    11-常用SQL总结
    10-SQLServer中统计信息的使用
    Java连接mysql数据库
    递归方式的对变量中的特殊字符进行转义/去除转义
  • 原文地址:https://www.cnblogs.com/kikokiko/p/13192908.html
Copyright © 2011-2022 走看看