#include using namespace std; const int N = 2e5 + 10, M = 2e6 + 10; //链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } int dfn[N], low[N], stk[N], top, timestamp; vector bcc[N]; int bcnt; unordered_set in; int n, m; int ans1, ans2, ans3; void deal_circle() { int sum = 0; for (int u : bcc[bcnt]) for (int j = h[u]; ~j; j = ne[j]) if (in.count(e[j])) sum++; //此边的两个点都在点双中,则此边在点双中 sum /= 2; //因为a->b,b->a都sum++,重复了,需要除以2,才是边数 //边数大于点数,嵌套环,每条边都是冲突边 if (sum > bcc[bcnt].size()) ans2 += sum; //判定割边 (第二种判定割边的办法) //此处写ans3+=sum 或 ans3+=1是一个意思,因为此时只能是两点一线的情况,否则就不是点双。特殊的点双只有一条割边 if (sum < bcc[bcnt].size()) ans3 += sum; } void tarjan(int u, int fa) { low[u] = dfn[u] = ++timestamp; stk[++top] = u; int son = 0; //子节点个数 for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j == fa) continue; if (!dfn[j]) { son++; //找到一个子节点 tarjan(j, u); low[u] = min(low[u], low[j]); //第一种判定割边的办法 //参阅一下判割边的模板代码 if (low[j] > dfn[u]) ans1++; if (low[j] >= dfn[u]) { int x; bcnt++; //针对每个点双而言,都在dfs过程中记录此点双中有哪些点,避免后期二次统计,造成速度下降TLE in.clear(); do { x = stk[top--]; bcc[bcnt].push_back(x); in.insert(x); //增加点双中有哪些点的记录信息 } while (x != j); bcc[bcnt].push_back(u); in.insert(u); //增加点双中有哪些点的记录信息 deal_circle(); //在完成点双的记录后,马上开始统计,以免将所有的点双中点的信息完整记录下来,造成MLE,TLE等问题 } } else low[u] = min(low[u], dfn[j]); } //特判独立点 if (fa == -1 && son == 0) bcc[++bcnt].push_back(u); } int main() { //文件输入输出 #ifndef ONLINE_JUDGE freopen("HDU3394.in", "r", stdin); #endif while (~scanf("%d%d", &n, &m) && n + m) { // ans1:割边数量 ans2:冲突边数量,也就是点双中所有边的数量,它们都是存在多个环中 ans3:也是割边的数量,与 ans1相同,但实现的方式不一样 ans1 = ans2 = ans3 = idx = top = timestamp = 0; memset(dfn, 0, sizeof dfn); memset(h, -1, sizeof h); // memset(low, 0, sizeof low); //low数组不用重新初始化 while (m--) { int a, b; scanf("%d %d", &a, &b); a++, b++; //避开下标0,向右推一个,使得下面的 tarjan算法的模板不变 if (a != b) add(a, b), add(b, a); //防止重边 } // tarjan求点双的模板 for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, -1); //下面无论是取 ans1还是ans3都是一样的 printf("%d %d\n", ans1, ans2); // printf("%d %d\n", ans3, ans2); } return 0; }