• 【题解】Atcoder ARC#76 F-Exhausted?


      第一次用霍尔定理做题..简单的来说,就是判断一张二分图上是否存在完美匹配,只需要证明对于 (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;
    }
  • 相关阅读:
    新版眼保健操图解(转)
    新经理从IBM来
    宝宝六个月零五天,从床上摔下。。。。。
    [转] 教小朋友画画
    宝宝辅食食谱(4、5、6、7个月)
    永远的乔布斯
    北京一场大暴雨,暴出几句经典语
    [转] 想做永久夫妻就要看
    宝宝身高和体重踪迹
    go语言基础之包和自定义包与main包
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9693439.html
Copyright © 2020-2023  润新知