【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

其他 ·发表 2018-08-23

r+ uil mat amp con pan com cnblogs 找出最大值

 

题面

题目大意:

给你\(m\)张椅子,排成一行,告诉你\(n\)个人,每个人可以坐的座位为\([1,l]\bigcup[r,m]\) ,为了让所有人坐下,问至少还要加多少张椅子。

Solution:

  • 为什么加椅子? 我们可以在最左边或最右边一直加直到人人都有座位。
  • 首先这道题目抽象成二分图很简单,然后我们可以只要求解出人与座位的最大匹配是多少,总人数减去即可,但跑二分图最大匹配显然会超时,我们就可以往霍尔定理方面想。
  • 然后你还需要知道一个霍尔定理推论:假设某个人的集合为\(X\) ,这个集合所对应的椅子的集合为\(Y\) ,如果\(|X|\leq|Y|\ ) ,则具有完美匹配,如果\(|X|\geq|Y|\) ,则\(X\)至少要删去\(|X|-|Y|\)个元素,才能有完备匹配,我们定义\(\Gamma(X)=|X|-|Y|\) 。

技术分享图片

在这题里,这个就是至少需要添加的椅子数目,所以我们要找出最大的\(\Gamma(X)\)

  • 接下来我们就来分析怎么找出最大的\(\Gamma(X)\) ,因为\(X\)不具有任何性质,不好下手,我们考虑\(Y\)有啥特点,他一定是\([1,l]\bigcup[r,m]\) ,然后我们可以通过这个\(Y\)确定\(|X|\) ,所以会有一下做法

法一:暴力枚举

  • 暴力枚举\(l,r\) ,椅子的个数为\(l+m-r+1\) ,通过上面的定理处理出答案,找出\(\Gamma\)最大值。 时间复杂度: \(O(n^2)\) 貌似会更高到三方

法二:与其说是法二不如说是法一优化

  • 我们考虑上面的算法哪一些地方是冗余的。 假设我们枚举出\(l\) ,根据法一,我们会枚举出所有的\(r\) ,显然不用枚举所有的,实际上只有找出这个\(l\)对应后面的\ (r\)算出来的最大值,如何快速查询出最大值,我们考虑使用线段树。
  • 具体如何优化这个问题:计算式子是人数 \(-(l+m-r+1)\) 。
  • 因为固定了\(l\) ,我们可以确定现在最多有多少人,总人数与\(l'\)有关( \(l'<l\) )所以我们把\(l\)从小到大排序,把人数不断往线段树里面丢。
  • 具体多少人根据\(r\)决定,某一个人要加入计算的人数内,必须是他所允许的所有椅子范围都在讨论范围内,比如这个\(l=l_i\) ,那么\(r<= r_i,r>=0\)的人数都可以加一(因为我们此时\(l\)是固定的,保证了这个人\(l\)在范围内,如果枚举的\(r\geq r_i\) ,那么这个人数是要算进去的)。
  • 如果上面你看懂了,那就很好办了,我们会发现对于枚举的\(r\) ,式子中的人数 \(-m-1+r\)是一样的, 人数我们是在推进\(l\)同时加入线段树, \(-m-1+r\)我们就可以提前加入线段树(建树)
  • 对于一种特殊的情况,比如说: \(l_i=1,r_i=1\) ,那么他能放的范围为所有,所以我们要判断\(mn\)为答案的情况
  • 对于普通枚举\(l\) ,我们没必要考虑全部集合情况,所以我们就只用在线段树\(l+2\rightarrow m+1\)找出最大值减去\(l\) ,得到的答案与\(ans\)取\(max\)就\(ok\)啦

  • 下面我们来将 乱搞 做法,我们把人按\(l\)排序,枚举到人后把他可以座椅子的范围用线段树标记,然后算出总可以坐的椅子数与人数相比较,求出每次\( ans\)的\(max\) ,一开始错两个点,然后排了两个序,算两次就只错一个点了。 这个方法显然是不对哒! ! 因为显然有一些人的子集没有枚举到。

这道题好理解吧 (毛线,我起码看了一个下午才看懂,去吃饭的路上突然懂了23333)

对了贪心也可以过这道题,只不过做法没这么优美罢了

Attention:

  1. 线段树是从\(0\rightarrow m+1\) ,因为人的\(l,r\)包含\(0,m+1\)
  2. 特殊情况, \(|X|=n\)
  3. 枚举出\(l\)后,找最大值一定是从\([l+1,m+1]\)中找

    First,你枚举的\(r\)要\(>l\) 。 
    Second, \(|X|=n\)已经被考虑(没那个必要了,其实你从\(l+1\)开始也不影响)

Code:

//It is coded by ning_mew on 7.16 #include<bits/stdc++.h> #define ls(x) (x*2) #define rs(x) (x*2+1) using namespace std; const int maxn=2e5+7,inf=1e9+7; int n,m,ans=0; struct Opt{int l,r;}p[maxn]; struct Node{int lazy,maxx;}node[maxn*4]; bool cmp(const Opt &A,const Opt &B){return Al<Bl;} void pushdown(int num,int nl,int nr){ if(!node[num].lazy)return; int lz=node[num].lazy; node[num].lazy=0; node[ls(num)].maxx+=lz;node[ls(num)].lazy+=lz; node[rs(num)].maxx+=lz;node[rs(num)].lazy+=lz; } void update(int num){node[num].maxx=max(node[ls(num)].maxx,node[rs(num)].maxx);} void build(int num,int nl,int nr){ node[num].lazy=0; if(nl==nr){node[num].maxx=nr-m-1;return;} int mid=(nl+nr)/2; build(ls(num),nl,mid);build(rs(num),mid+1,nr); update(num); } void add(int num,int nl,int nr,int ql,int qr,int ad){ if(ql<=nl&&nr<=qr){node[num].maxx+=ad;node[num].lazy+=ad;return;} if(nr<ql||qr<nl)return; int mid=(nl+nr)/2;pushdown(num,nl,nr); add(ls(num),nl,mid,ql,qr,ad);add(rs(num),mid+1,nr,ql,qr,ad); update(num);return; } int quary(int num,int nl,int nr,int ql,int qr){ if(ql<=nl&&nr<=qr)return node[num].maxx; if(nr<ql||qr<nl)return -inf; int mid=(nl+nr)/2;pushdown(num,nl,nr); return max(quary(ls(num),nl,mid,ql,qr),quary(rs(num),mid+1,nr,ql,qr)); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d%d",&p[i].l,&p[i].r); sort(p+1,p+n+1,cmp);p[n+1].l=inf; build(1,0,m+1); for(int i=1;i<=n;i++){ add(1,0,m+1,0,p[i].r,1); if(p[i].l!=p[i+1].l&&p[i].l<=m-1)ans=max(ans,quary(1,0,m+1,p[i].l+2,m+1)-p[i].l); }ans=max(ans,nm);printf("%d\n",ans); return 0; } 

博主蒟蒻,随意转载。 但必须附上原文链接:http://www.cnblogs.com/Ning-Mew/,否则你会场场比赛暴0! ! !

【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值