首页 > 技术文章 > loj10104 [POI 2008]Blockade

yzxverygood 2018-08-24 19:20 原文

传送门

分析

我们知道对于一个割点,我们如果去掉它就会使原来的图被分为若干块,则这是我们将所有块包含的点的个数两两相乘即可,而如果不是割点则对于图的连通性没有影响。注意在最后要加上2*(n-1)表示去掉的那个点对答案产生的贡献。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
long long dfn[100010],low[100010],cnt,sum,siz[100010];
long long ans[100010],n,m;
vector<long long>v[100010];
inline void tarjan(long long x,long long la){
      siz[x]=1;
      dfn[x]=low[x]=++cnt;
      long long son=0,tot=0;
      for(long long i=0;i<v[x].size();i++)
        if(v[x][i]!=la){
          if(!dfn[v[x][i]]){
              son++;
              tarjan(v[x][i],x);
            siz[x]+=siz[v[x][i]];
              low[x]=min(low[x],low[v[x][i]]);
              if(dfn[x]<=low[v[x][i]]){
                ans[x]+=siz[v[x][i]]*tot;
                tot+=siz[v[x][i]];
              }
          }else low[x]=min(low[x],dfn[v[x][i]]);
        }
      ans[x]+=tot*(n-tot-1);
      if(son==1&&!la)ans[x]=0;
}
int main(){
      long long i,j,k;
      scanf("%lld%lld",&n,&m);
      for(i=1;i<=m;i++){
          long long x,y;
          scanf("%lld%lld",&x,&y);
          v[x].push_back(y);
          v[y].push_back(x);
      }
      for(i=1;i<=n;i++)
        if(!dfn[i])tarjan(i,0);
      for(i=1;i<=n;i++)printf("%lld\n",(ans[i]+n-1)*2);
      return 0;
}

推荐阅读