题意:
模板题,求图中每个割点能把网络分成几个点双连通分量(不是割点就输出他有几块即可)。

题解:
跟POJ 的SPF很像

这题用Tarjan来求,首先我们需要统计出来具体有几个连通块。
对于每个连通块,我们需要判断这个割点去掉后,这幅图会被分成几块?
这个其实很简单,只需要更改一下判断这个点是否为割点即可。
每被判断成一个割点,那么这个割点++。
注意特判根节点! 看看它有几个不相连的子树

num[]代表的是 从这个点分支出去,有几个不相连的子树

到最后的时候要进行num[i]--,是因为他是头节点。(画个图理解一下)

num[i]--;
/*Keep on going Never give up*/
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>

#define int long long
#define endl '\n'
#define Accepted 0
#define AK main()
#define I_can signed
using namespace std;
const int maxn =3e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
using namespace std;
vector<int> edge[maxn];
int n,m;
int low[maxn];
int num[maxn],dfn[maxn];
bool visited[maxn];
int cnt,top;
void dfs(int u,int fa){
    visited[u]=true;
    low[u]=dfn[u]=++cnt;
    int ch=0;
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        if(!visited[v]){
            ch++;
            dfs(v,u);
            low[u]=min(low[v],low[u]);
            if(low[v]>=dfn[u])  num[u]++;
        }
        else if(dfn[v]<dfn[u]&&v!=fa){
            low[u]=min(dfn[v],low[u]);
        }
    }
//    if(u==top&&ch>=1){
//        num[u]=ch;
//    }
}
I_can AK
{
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    memset(visited,false,sizeof visited);
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    //dfs(1,-1);
    int ans=0;
    //cout<<visited[1]<<endl;
    for(int i=1;i<=n;i++){
        if(!visited[i]){
            ans++;
            //cout<<i<<endl;
            top=i;

            dfs(i,-1);
            num[i]--;
        }
    }
    //cout<<ans<<endl;
    //cout<<num[1]<<endl;
    for(int i=1;i<=n;i++){
        cout<<num[i]+ans<<" ";
    }
    return 0;

}