arc076 F

题目链接

Problem Statement
There are M chairs arranged in a line. The coordinate of the i-th chair ($$$1≤i≤M$$$) is $$$i$$$.
N people of the Takahashi clan played too much games, and they are all suffering from backaches. They need to sit in chairs and rest, but they are particular about which chairs they sit in. Specifically, the i-th person wishes to sit in a chair whose coordinate is not greater than Li, or not less than $$$R_i$$$. Naturally, only one person can sit in the same chair.
It may not be possible for all of them to sit in their favorite chairs, if nothing is done. Aoki, who cares for the health of the people of the Takahashi clan, decides to provide additional chairs so that all of them can sit in chairs at their favorite positions.
Additional chairs can be placed at arbitrary real coordinates. Find the minimum required number of additional chairs. Constraints
Input
Input is given from Standard Input in the following fomat:
$$$N$$$ $$$M$$$
$$$L_1$$$ $$$R_1$$$
:
$$$L_N$$$ $$$R_M$$$
Output
Print the minimum required number of additional chairs.

Input
4 4
0 3
2 3
1 3
3 4
Output
0
Input
7 6
0 7
1 5
3 6
2 7
1 6
2 6
3 7
Output
2
Input
3 1
1 2
1 2
1 2
Output
2
Input
6 6
1 6
1 6
1 5
1 5
2 6
2 6
Output
2

参考了这篇大佬的博客

【题意】

有$$$m$$$个座位,分别位于坐标为$$$1, 2, 3, ..., m$$$的地方;$$$n$$$个客人,第$$$i$$$位客人只坐位于$$$[0, l_i]cup[r_i, infty]$$$的座位。每个座位只能坐一个人,问最少需要添加几个座位才能使所有人坐下?

【分析】

首先说明一下霍尔定理的前提,已知点集X=$$${x_1, x_2, ..., x_n}$$$, Y=$$${y_1, y_2, ..., y_m}$$$,和边集E,E中每条边只能连接 X 与 Y 中的一对点;如果X中的k个点各自经过E与Y中k个不同的点相连,则称形成了一个大小为k的配对。

霍尔定理给出了在X中存在n个点的配对的充分必要条件——对任何一个大小为k的X(k≤n)的子集,Y至少有k个点经过E与它们相连。用公式来表达就是,定义$$$omega$$$(X)表示Y中一共有几个点经过E与集合X相连,那么霍尔定理就是 $$$forall$$$ X$$$_1$$$ $$$subset$$$ X, |X$$$_1$$$| ≤ |$$$omega$$$(X$$$_1$$$)|

在这道题中,可以这样使用霍尔定理:假设添加t个座位后,所有人都能坐下,也就是存在n个人的配对,那么一定满足对任意一个客人的集合X,有

|X| ≤ |$$$omega$$$(X)+t|

$$$Leftrightarrow$$$ |X| ≤ |$$$omega$$$(X)| +t

$$$Leftrightarrow$$$ |X| - |$$$omega$$$(X)| ≤ t

 那么t的最小值就是 max{ |X| - |$$$omega$$$(X)| },因为$$$omega$$$(X)一定是[1, L]$$$cup$$$[R,m]的形式,可以改写为L + m - R +1

答案整理为max{ |X| + R - L - m -1 },在霍尔定理的帮助下,解题思路转化为,只需要遍历所有的客人的子集,就能算出来最大值了,不过遍历子集的代价太大,可以转而遍历(L, R)的区间。若固定L,只需要求max{ |X| + R },这个操作可以用线段树来完成,对每个L,处理每个R$$$_i$$$都让[L, R$$$_i$$$]内的数全部+1,为了选择最大的|X| + R,可以把所有结点初始化为R。

由于只关心固定L,[X]+R最大值,为了降低复杂度,可以直接在L$$$_1$$$处理完的基础上继续处理L$$$_2$$$的每个R$$$_i$$$,也就是说L$$$_2$$$不再单独考虑,直接和小的L结合到一起。

【代码】

因为使用了线段树,所以代码量略大,如果不看线段树的代码,其实核心部分很简洁。

#include <stdio.h>
#include <vector>
using std::vector;

#define  N_max 200005

#define  left(x) ((x)<<1)
#define right(x) (((x)<<1)|1)
#define  mid(l,r) (l+((r-l)>>1))
#define  max(a,b) ((a)>(b)?(a):(b))
int lch[N_max << 2], rch[N_max << 2], lzy[N_max << 2], val[N_max << 2];

inline void lzydown(int cur)
{
    if(lzy[cur])
    {
        int l = left(cur), r = right(cur);
        lzy[l] += lzy[cur];
        lzy[r] += lzy[cur];
        val[l] += lzy[cur];
        val[r] += lzy[cur];
        lzy[cur] = 0;
    }
}

inline void updup(int cur)
{
    val[cur] = max(val[left(cur)], val[right(cur)]);
}

void build(int cur, int cl, int cr)
{
    lch[cur] = cl; rch[cur] = cr;
    if (cl == cr) {
        val[cur] = cr;
        return;
    }
    int m = mid(cl, cr);
    build(left(cur), cl, m);
    build(right(cur), m + 1, cr);
    updup(cur);
}

void add(int cur,int cl,int cr)
{
    if(lch[cur]==cl&&rch[cur]==cr)
    {
        lzy[cur]++;
        val[cur]++;
        return;
    }
    lzydown(cur);
    int m = mid(lch[cur],rch[cur]);
    if (cr <= m)
    {
        add(left(cur), cl, cr);
    }
    else if(cl>m)
    {
        add(right(cur), cl, cr);
    }
    else
    {
        add(left(cur), cl, m);
        add(right(cur), m + 1, cr);
    }
    updup(cur);
}

int query(int cur,int cl,int cr)
{
    if (lch[cur] == cl&&rch[cur] == cr)
    {
        return val[cur];
    }
    int m = mid(lch[cur], rch[cur]);
    lzydown(cur);
    if (cr <= m)
    {
        return query(left(cur), cl, cr);
    }
    else if (cl>m)
    {
        return query(right(cur), cl, cr);
    }
    else
    {
    int ql=    query(left(cur), cl, m);
    int qr=    query(right(cur), m + 1, cr);
    return max(ql, qr);
    }
    return -1;
}

vector<int> ipt[N_max];
int ans = 0;
int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    ans = max(0,n - m);
    int a[2];
    for(int i=0;i<n;++i)
    {
        scanf("%d %d", a, a + 1);
        ipt[a[0]].push_back(a[1]);
    }
    build(1, 0, m + 1);
    for(int l=0;l<=m;++l)
    {
        int sz = ipt[l].size();
        for(int t=0;t<sz;++t)
        {
            int r = ipt[l][t];
            add(1, 0, r);
        }
        int temp = query(1, l + 1, m + 1) - m - l - 1;
        ans = max(ans, temp);
    }
    printf("%d", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/tobyw/p/9347092.html