第一次用霍尔定理做题..简单的来说,就是判断一张二分图上是否存在完美匹配,只需要证明对于 (a) 集合中的任意 (k) 个点来说,都与 (b) 集合中的 (k) 个点有边相连。如果不满足,那么最大匹配数就是两个集合中有连边的点数最大的差。
这道题目二分图匹配的解法是非常显然的,让 (i) 点和对面的 (1 -> l[i]), (r[i] -> m) 点连边,判断是否存在完美匹配即可。但点数太多了,我们考虑使用霍尔定理来求解。如果我们固定右边选择的点为 (1->l[i]), (r[i] -> m),那为了判断是否满足我们自然要尽量地使得左边的点数更大(如果在最大情况下依然合法,也就说明的确是存在完美匹配的,当然这也提示我们霍尔定理就是要寻找题目的特殊性质,固定一边的点数来考虑最坏的情况)。要使左边的点数最大,显然我们应该选入所有 (l -> r) 在这个范围内的点。所以我们可以使用扫描线降维维护最值。(~ ̄▽ ̄)~
#include <bits/stdc++.h> using namespace std; #define maxn 2000000 #define INF 99999999 int n, m, mn[maxn], mark[maxn]; int ans = INF; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } struct node { int l, r; friend bool operator <(const node& a, const node& b) { return a.r > b.r; } }P[maxn]; void push_down(int p) { if(!mark[p]) return; mark[p << 1] += mark[p], mark[p << 1 | 1] += mark[p]; mn[p << 1] += mark[p], mn[p << 1 | 1] += mark[p]; mark[p] = 0; } void Update(int p, int l, int r, int L, int R, int x) { if(L <= l && R >= r) { mn[p] += x; mark[p] += x; return; } if(L > r || R < l) return; int mid = (l + r) >> 1; push_down(p); Update(p << 1, l, mid, L, R, x); Update(p << 1 | 1, mid + 1, r, L, R, x); mn[p] = min(mn[p << 1], mn[p << 1 | 1]); } void Build(int p, int l, int r) { if(l == r) { mn[p] = l; return; } int mid = (l + r) >> 1; Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r); mn[p] = min(mn[p << 1], mn[p << 1 | 1]); } int Query(int p, int l, int r, int x) { if(l == r) return mn[p]; int mid = (l + r) >> 1; push_down(p); if(x <= mid) return Query(p << 1, l, mid, x); else return Query(p << 1 | 1, mid + 1, r, x); } int main() { n = read(), m = read(); for(int i = 1; i <= n; i ++) P[i].l = read(), P[i].r = read(); sort(P + 1, P + 1 + n); int now = 1; Build(1, 0, m); for(int i = m + 1; i >= 0; i --) { while(now <= n && P[now].r >= i) Update(1, 0, m, P[now].l, m, -1), now ++; Update(1, 0, m, i, m, -1); ans = min(ans, (m - i + 1) + mn[1]); } if(ans < 0) printf("%d ", -ans); else printf("0 "); return 0; }