AtCoder ARC076 F

题目链接:ARC076 F - Exhausted?

题意:

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

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

(1leq N,M leq 2 imes 10^5)

(0leq L_i<R_ileq M+1(1leq ileq N))

思路:

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

题目中 (leq L_i)(geq R_i) 的限制看起来很麻烦,把它取反,只需要维护 (min_{iin X}{R_i})(max_{iin X}{L_i}) ,我们把左边界 (L_i) 定下来,那么要求的即 (sum_{j=1}^N[L_jleq L_i][R_jgeq k]-(M-(k-L_i+1))) 的最大值,把 (M)(-L_i+1) 扔出来,即使(sum_{j=1}^N[L_jleq L_i][R_jgeq k]+k) 最大,可以线段树扫描线维护,位置 (i) 的值初始为 (i) 本身(即 ("+k")),根据 (L_i) 从左往右扫描,处理完一个人就给 ([0,R_i])(1) ( (kin[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;
}
原文地址:https://www.cnblogs.com/Neal-lee/p/14472821.html