标签:
题意读懂了就好做了,就是求一下点双连通分量。维护一下一颗子树的结点数,对于一个结点当u是割点的时候,
统计一下u分割的连通分量v,每得到一个连通分量的结点数cnt(v)和之前连通分量结点数sum相乘一下就好。最后加一下和u的子树上的连通分量总数和其它的结点的乘积。
B,C中其中一者可以是A,所有最后还要加上n-1。
补下以前的题
#include<bits/stdc++.h> using namespace std; int n,m; const int maxn = 20005; vector<int> G[maxn]; #define PB push_back int dfn[maxn],low[maxn],dfs_clock,ans[maxn],cnt[maxn]; void tarjan(int u,int fa = -1) { dfn[u] = low[u] = ++dfs_clock; cnt[u] = 1; ans[u] = 0; int sum = 0; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(!dfn[v]){ tarjan(v,fa); if(low[v]>=dfn[u]){ ans[u] += sum*cnt[v]; sum += cnt[v]; } low[u] = min(low[v],low[u]); cnt[u] += cnt[v]; }else if(v != fa && dfn[v] < dfn[u] ) { low[u] = min(low[u],dfn[v]); } } ans[u] += (n-sum-1)*sum; } int main() { freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); cin>>n>>m; for(int i = 0; i < m; i++){ int u,v; scanf("%d%d",&u,&v); G[u].PB(v); G[v].PB(u); } tarjan(1); for(int i = 1; i <= n; i++) printf("%d\n",ans[i]+n-1); return 0; }
标签:
原文地址:http://www.cnblogs.com/jerryRey/p/4770915.html