zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    在vs2010里使用EF4.3的Code First个人使用笔记
    如何充分利用C#匿名方法的平台优势(转)
    打开Microsoft SQL Server Management Studio 2005非常慢,特别慢的原因
    PowerShell msbuild
    很久没写了
    第一篇博客,逗大家一笑
    以编程方式调用按钮1(button1)的 Click 事件
    VS2010删除已安装的联机模板
    创建和分享你的Visual Studio color
    异步获取CMD命令行输出内容
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14472821.html
Copyright © 2011-2022 走看看