AtCoder ARC076 F - Exhausted?

题目链接:ARC076 F - Exhausted?

题意:

一行摆了 \(M\) 张椅子,第 \(i\) 张椅子的位于 \(i\) 的位置。有 \(N\) 个人想坐在椅子上休息,第 \(i\) 个人希望自己坐在一张坐标 \(\leq L_i\)\(\geq R_i\) 的椅子,且一张椅子只能坐一个人。

由于不一定所有人都能坐到合适的椅子上,\(Aoki\) 会额外提供一些,这些椅子可以放在任意实数的坐标处,请问最少需要多少张额外的椅子。

\(1\leq N,M \leq 2\times 10^5\)

\(0\leq L_i<R_i\leq M+1(1\leq i\leq N)\)

思路:

把人和椅子分别作为左右部节点,那便是二分图匹配,答案为 \(N\) 减去最大匹配,不过这么做显然不够优秀,想一想还有什么别的计算最大匹配的方法,有!通过霍尔定理(\(Hall's\) \(Theorem\)),这里的答案应为 \(max\{|X|-|\Gamma (X)|\}\)\(0\) 取较大值,\(X\) 为左部节点的任意一个子集, \(\Gamma (X)\)\(X\) 的邻居节点集。

题目中 \(\leq L_i\)\(\geq R_i\) 的限制看起来很麻烦,把它取反,只需要维护 \(\min_{i\in X}\{R_i\}\)\(\max_{i\in X}\{L_i\}\) ,我们把左边界 \(L_i\) 定下来,那么要求的即 \(\sum_{j=1}^N[L_j\leq L_i][R_j\geq k]-(M-(k-L_i+1))\) 的最大值,把 \(M\)\(-L_i+1\) 扔出来,即使\(\sum_{j=1}^N[L_j\leq L_i][R_j\geq k]+k\) 最大,可以线段树扫描线维护,位置 \(i\) 的值初始为 \(i\) 本身(即 \("+k"\)),根据 \(L_i\) 从左往右扫描,处理完一个人就给 \([0,R_i]\)\(1\) ( \(k\in[0,R_i]\) 时自己会被算进去),每次询问 \([L_i+1,R_i]\) 上最大值( 由于是开区间 ,\(L_i\)\(k\) 不能重合)。

注意到当 \(\Gamma (X)\) 覆盖了整个 \(M\) 的区域时,\(M-(k-L_i+1)\) 这么算是不对的,所以要先另外处理好,作为 \(ans\) 的初始值即可。

Code:

#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,b,a) for(int i=(b);i>=(a);i--)
#define N 200200
using namespace std;
struct guest{
    int l,r;
}a[N];
struct SegmentTree{
    int l,r,mx,lazy;
}t[4*N];
int n,m;
void build(int x,int l,int r){
    t[x].l=l,t[x].r=r;
    if(l==r){t[x].mx=l;return;}
    int mid=(l+r)>>1;
    build(x*2,l,mid),build(x*2+1,mid+1,r);
    t[x].mx=max(t[x*2].mx,t[x*2+1].mx);
}
void pushdown(int x){
    if(t[x].lazy){
        t[x*2].mx+=t[x].lazy,t[x*2].lazy+=t[x].lazy;
        t[x*2+1].mx+=t[x].lazy,t[x*2+1].lazy+=t[x].lazy;
        t[x].lazy=0;
    }
}
void update(int x,int left,int right,int k){
    if(t[x].l>=left&&t[x].r<=right){
        t[x].mx+=k,t[x].lazy+=k; return;
    }
    pushdown(x);
    int mid=(t[x].l+t[x].r)>>1;
    if(mid>=left)update(x*2,left,right,k);
    if(mid<right)update(x*2+1,left,right,k);
    t[x].mx=max(t[x*2].mx,t[x*2+1].mx);
}
int query(int x,int left,int right){
    if(t[x].l>=left&&t[x].r<=right)return t[x].mx;
    int mid=(t[x].l+t[x].r)>>1,res=0;
    pushdown(x);
    if(mid>=left)res=max(res,query(x*2,left,right));
    if(mid<right)res=max(res,query(x*2+1,left,right));
    return res;
}
bool cmp(guest a,guest b){return a.l<b.l;}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    rep(i,0,n-1)cin>>a[i].l>>a[i].r;
    build(1,0,m+1);
    sort(a,a+n,cmp);
    int lm=m+1,rm=0;
    rep(i,0,n-1)lm=min(lm,a[i].r),rm=max(rm,a[i].l);
    int ans=n+(rm<lm?lm-rm-1:0);
    rep(i,0,n-1){
        ans=max(ans,query(1,a[i].l+1,a[i].r)-a[i].l);
        update(1,0,a[i].r,1);
    }
    cout<<max(ans-m,0)<<endl;
    return 0;
}
posted @ 2021-03-03 10:03  Neal_lee  阅读(60)  评论(0编辑  收藏  举报