转载自@vufw_795
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
#define pb(a) push_back(a)
#define fir first
#define se second
#define LL unsigned long long
typedef pair<int,int> pii;
typedef pairint> pli;
typedef pair pll;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
LL mod = 1e9+7;
struct node
{
int x,y;
node(int a=0, int b=0)
{
x=a;y=b;
}
}tn;
//blocks[]存每个块包含的点,bridge存是桥的边
vector<int>g[maxn],blocks[maxn];
vector bridge;
stack st;
// 深度优先搜索访问次序, 能追溯到的最早的次序
int dfn[maxn],low[maxn];
bool vis[maxn];
// 索引号,块的个数
int index,cnt,ans1,ans2;
int n,m;
void init()
{
for(int i=0;iwhile(!st.empty())st.pop();
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
index = cnt = 1;
ans1 = ans2 = 0;
}
void judge(int u,int v)
{
int x,y,c1 = 0,c2 = 0;
node temp;
memset(vis,false,sizeof(vis));
while(!st.empty())
{
c1++;
temp = st.top();st.pop();
x=temp.x;y=temp.y;
if(!vis[y]) c2++,blocks[cnt].push_back(y),vis[y]=true;
//一直到最后一条树枝边为止,起点并不属于这个双连通分量,如果属于,已在后向边中加入。
if(x==u) break;
if(!vis[x]) c2++,blocks[cnt].push_back(x),vis[x]=true;
}
if(c1 > c2) ans2 += c1;
cnt++;
}
void tarjan(int x,int fa)
{
low[x] = dfn[x] = index++;
int len = g[x].size();
for(int i=0;iint t=g[x][i];
if(t==fa)
continue;
if(!dfn[t] && dfn[t]//加入树枝边
st.push(node(x,t));
tarjan(t,x);
low[x] = min(low[x], low[t]);
if(dfn[x]<=low[t]) {
if(dfn[x] < low[t]) {
ans1++;
}
judge(x,t);
}
if(dfn[x]else if(dfn[t] < dfn[x])
{
//加入后向边
st.push(node(x,t));
low[x] = min(low[x], dfn[t]);
}
}
}
int solve()
{
for(int i = 1; i <= n; i++)
if(!dfn[i]) {
tarjan(i,i);
}
return cnt;
}
int main() {
while(cin>>n>>m && (n || m)) {
init();
for(int i = 1;i <= m;i++) {
int u,v;
scanf("%d%d",&u,&v);
g[u+1].pb(v+1);
g[v+1].pb(u+1);
}
solve();
printf("%d %d\n",ans1,ans2);
}
}
struct Edge{
int u,v;
Edge(int u=0,int v=0):u(u),v(v){}
}e[maxm];
int n,m,stamp,dfn[maxn],low[maxn],bccno[maxn],bcc_cnt;
vector<int> vec[maxn],bcc[maxn];
bool g[maxn][maxn],isbridge[maxm];
void tarjan(int index,int fa)
{
int tmp;
dfn[index]=low[index]=++stamp;
for(int i=0;iif(!dfn[tmp])
{
tarjan(tmp,index);
low[index]=min(low[index],low[tmp]);
if(low[tmp]>dfn[index])
isbridge[vec[index][i]]=isbridge[vec[index][i]^1]=1;
}
else if(dfn[tmp]void dfs(int index)
{
dfn[index]=1;
bccno[index]=bcc_cnt;
for(int i=0;iint tmp=vec[index][i];
if(isbridge[tmp])
continue;
if(!dfn[e[tmp].v])
{
dfs(e[tmp].v);
}
}
}
void find_ebcc(){
bcc_cnt=stamp=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(isbridge,0,sizeof(isbridge));
memset(bccno,0,sizeof(bccno));
memset(bcc,0,sizeof(bcc));
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i, -1);
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
bcc_cnt++;
dfs(i);
}
}
}