zoukankan      html  css  js  c++  java
  • 1123: [POI2008]BLO

    1123: [POI2008]BLO

    Time Limit: 10 Sec  Memory Limit: 162 MB
    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1123

    Description

    Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

    Input

    输入n<=100000 m<=500000及m条边

    Output

    输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

    Sample Input

    5 5
    1 2
    2 3
    1 3
    3 4
    4 5

    Sample Output

    8
    8
    16
    14
    8

    题意叙述不清。

    题目大意:给定N个点M条边的无向图,问删除每个点后,对于有序数对(x,y)满足x,y互不连通的数对数。其中,被删掉的点也应被统计。

    这种和删点,联通有关的,可以考虑割点/点双联通分量。

    题解:这一题中蕴含的技巧就是求割点时计算其将图分成了多少个大小为多少的连通块。 
    因为答案就是这些连通块大小互相乘的和。 
    关键在于,再求割点时维护一个vis[i]代表搜索树中这个子树的大小。 
    因为一个割点将图分成的连通块是其下面的所有子树(互不相连)与这个点上面的所有点。tmp表示这个点的子树之前的同父亲子树的和。为什么这么算可以得到答案,可以自己推一推。 
    不要忘记最后答案要乘2。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn = 100005, maxm = 1000005;
    int n,m,dfn[maxn],tot,low[maxn],idx,h[maxn];
    ll siz[maxn], ans[maxn];
    struct edge{
        int v,nxt;
    }G[maxm];
    void add(int u, int v){
        G[++tot].v = v;G[tot].nxt = h[u]; h[u] = tot;
    }
     
    void tarjan(int u, int f){
        dfn[u] = low[u] = ++idx;
        siz[u] = 1;
        ll t = 0;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(v == f)continue;
            if(dfn[v])low[u] = min(low[u], dfn[v]);
            else {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
                siz[u] += siz[v];
                if(dfn[u] <= low[v]){//
                     
                    ans[u] += siz[v] * t;
                    t += siz[v];            
                }
            }
        }
        ans[u] += (n - t - 1) * t;
    }
     
    int main(){
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= m; i++){
            int u, v;
            scanf("%d%d",&u,&v);
            add(u, v); add(v, u);
        }
        for(int i = 1; i <= n; i++)
            if(!dfn[i])tarjan(i, -1);
        for(int i = 1; i <= n; i++)
            printf("%lld
    ",(ans[i]+n-1)*2);
    }
    
    View Code
  • 相关阅读:
    Algs4-1.1.27二项分布
    Algs4-1.1.25数学归纳法证明欧几里得算法
    Algs4-1.1.26证明以下代码能够将a、b、c按照升序排列
    Algs4-1.1.24欧几里得算法求最大公约数
    Algs4-1.1.23区分在与不在白名单中的值
    Algs4-1.1.22以缩进方式打印递归参数
    微服务架构是什么?
    python 迭代器
    python 列表推导
    python 创建二维数组的方法
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9029346.html
Copyright © 2011-2022 走看看