2017国家集训队作业[arc076d/f][Exhausted?]
2017国家集训队作业[arc076d/f][Exhausted?]
题意:
有\(N\)个人,\(M\)把椅子,给出\(、、、L_i、R_i\)表示第\(i\)个人可以选择编号为\(1\sim L_i\)和\(R_i\sim M\)的椅子,求至少要加多少张椅子才能让每人都有椅子坐?(\(N,M\le2*10^5\))
题解:
场上看到这道题,woc,这不是sb的线段树或前缀和优化网络流建边二分图匹配吗?(这沙茶= =)
听dcx说,这题网络流建出来是分层图,流量是\(INF\)的可以贪心模拟?不会= =。
场后听到题解,还真是贪心,而且贪心方法五花八门。。。这里讲我最后用的方法。
按\(L_i\)排升序,枚举,若到第\(i\)个人时,\(L_i < i\),那就把前\(i\)个人中\(R_i\)最小的人匹配的椅子放到后半段去。优先队列维护。枚举\(R_i\)同理,注意终止边界就可以了。仔细想想,这贪心还挺对的,本蒟蒻场上满脑子优化建图还是太弱。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,l,r) for(int i=l;i<=r;i++)
#define of(i,l,r) for(int i=l;i>=r;i--)
#define fe(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
typedef long long ll;
inline int rd()
{
static int x,f;
x=0,f=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
const int N=200010;
struct node{int l,r;bool bo;}a[N];
int n,m,l,r,ans=0;
bool cmpl(node a,node b){return (a.l==b.l)?a.r>b.r:a.l<b.l;}
bool cmpr(node a,node b){return a.r>b.r;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ina.txt","r",stdin);
#endif
n=rd();m=rd();
l=1;r=m;
fo(i,1,n)a[i].l=rd(),a[i].r=rd();
sort(a+1,a+n+1,cmpl);
fo(i,1,n){
if(l>m)break;
if(l<=a[i].l){
ans++;l++;
a[i].bo=true;
}
}
sort(a+1,a+n+1,cmpr);
fo(i,1,n){
if(r<l)break;
if(!a[i].bo&&r>=a[i].r){
ans++;r--;
a[i].bo=true;
}
}
printf("%d\n",n-ans);
return 0;
}
UPD:2018/8/19 补上了代码