Half of the question came to mind, and the statistical answer after the last drawdown was hung up==....
Let's leave it alone. Ask how many edges you can add to make all the edges one-sided and two-sided.
N is a little small. I suspect there is n^2 water method.
It's obvious to find the shrinkage point after double edges, and then I'm a bit forced, I don't know how to count the answers.
Think about the strange posture of dp and dichotomy, but it seems useless.
Later, after reading a wave of problem solving, it was found that the conclusion== a tree, to let any two points have more than one path to connect, the answer is (number of leaf nodes + 1)/2.
Why? Because, a tree, we do not add edges at the beginning, the path between them must be upward and intersect, then the second path, we want to add as few edges as possible, and repeat as few edges as possible, so we can pair the leaf nodes between different subtrees, of course, if there is only one leaf node, two will be connected to the past.
Note that when the leaf nodes are finally counted, only the edge of the bridge is the edge of the tree.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n, m;
const int N = 1e5 + 5;
int read()
{
int x = 0, f = 1; char ch = getchar();
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x*f;
}
int dfn[N], low[N],dep[N];
bool vis[N],isc[N],isb[N];
int head[N], go[N], nxt[N];
int tot=1, cnt, tim;
inline void add(int x, int y)
{
go[++tot] = y;
nxt[tot] = head[x];
head[x] = tot;
}
inline void dfs(int x, int pre)
{
dfn[x]=low[x]=++tim;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
if ((i^1)!=pre)
if (!dfn[v])
dfs(v, i),
low[x] = min(low[x], low[v]);
else low[x] = min(low[x], dfn[v]);
}
if (pre&&low[x] == dfn[x])
isb[pre] = isb[pre ^ 1] = 1;
}
int bel[N];
inline void rebuild(int x, int num)
{
bel[x] = num;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
if (!bel[v] && !isb[i])rebuild(v, num);
}
}
int main()
{
n = read(), m = read();
fo(i, 1, m)
{
int x=read(), y=read();
add(x, y);
add(y, x);
}
int blocksum = 0;
fo(i, 1, n)if (!dfn[i])dfs(1,0);
fo(i, 1, n)if (!bel[i])rebuild(i, ++blocksum);
for (int i = 2; i <= tot; i += 2)if (isb[i])dep[bel[go[i]]]++, dep[bel[go[i ^ 1]]]++;
int ans = 0;
fo(i, 1, blocksum)if (dep[i] == 1)ans++;
printf("%d\n", (ans + 1) >> 1);
}