傳送門
先考慮樹,樹是一個二分圖。
看到是二分圖而且每次是對兩邊的同色的點反色能夠想到轉化:讓奇數層的點爲黑,偶數爲白,變成每次能夠交換兩個點的顏色。
把黑當作 \(-1\),白當作 \(1\),那麼求一個子樹和,考慮每一條邊的貢獻能夠獲得 \(ans=\sum_{i=1}^{n} |sum_i|\)
若是根的 \(sum\) 不爲 \(0\),那麼確定是無解的。
對於基環樹,先考慮奇環。
斷開奇環的一條邊 \((u,v)\),變成樹,\(u,v\) 確定是同一邊的點。
操做一次 \((u,v)\) 至關於能夠兩邊能夠同時新增長白點/黑點,也就是能夠把根的 \(sum\) 用這兩個點來變成 \(0\),(\(sum\) 必須爲偶數)平均分配以後用樹的作法便可。
考慮偶環。
斷開偶環的一條邊 \((u,v)\),變成樹,\(u,v\) 確定不是同一邊的點。
操做一次 \((u,v)\) 至關因而讓左右的點走了一次捷徑。
設用的次數爲 \(x\)。
若是一個點同時包含或不包含 \(u,v\) 兩個點,那麼 \(sum\) 必定不變。
不然加上或者減去 \(x\)。
至關是是要求 \(|x|+\sum |sum_i-x| + \sum |sum_i+x|\)
經典問題,排序以後取中位數便可。c++
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(1e5 + 5); struct Edge { int to, next; }; int n, m, first[maxn], cnt, sum[maxn], fa[maxn], dsu[maxn], deep[maxn], a, b, ans, val[maxn]; Edge edge[maxn << 1]; inline int Find(int x) { return (dsu[x] ^ x) ? dsu[x] = Find(dsu[x]) : x; } inline void Add(int u, int v) { edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++; edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++; } void Dfs(int u, int ff, int d) { int e, v; sum[u] = d; for (e = first[u]; ~e; e = edge[e].next) if ((v = edge[e].to) ^ ff) { deep[v] = deep[u] + 1; fa[v] = u, Dfs(v, u, -d); sum[u] += sum[v]; } } int main() { int i, u, v, len = 1; memset(first, -1, sizeof(first)); scanf("%d%d", &n, &m); if (n & 1) return puts("-1"), 0; for (i = 1; i <= n; ++i) dsu[i] = i; for (i = 1; i <= m; ++i) { scanf("%d%d", &u, &v); if (Find(u) ^ Find(v)) Add(u, v), dsu[Find(u)] = Find(v); else a = u, b = v; } if (!a) { Dfs(1, 0, 1); if (sum[1]) return puts("-1"), 0; } else { Dfs(a, 0, 1); if (deep[b] & 1) { if (sum[a]) return puts("-1"), 0; for (i = b; i ^ a; i = fa[i]) val[++len] = sum[i], sum[i] = 0; sort(val + 1, val + len + 1), v = val[(len + 1) >> 1]; for (i = 1; i <= len; ++i) ans += abs(val[i] - v); } else { if (sum[a] & 1) return puts("-1"), 0; v = sum[a] >> 1, ans = abs(v), sum[a] = 0; for (i = b; i ^ a; i = fa[i]) sum[i] -= v; } } for (i = 1; i <= n; ++i) ans += abs(sum[i]); printf("%d\n", ans); return 0; }