原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100187C.html
题目传送门 - CF-Gym100187C
题意
给定 $n$ 个房间以及 $n$ 个人。
第 $i$ 个房间的大小为 $a_i$。
第 $i$ 个人要的房间的大小范围为 $[L_i,R_i]$ 。
现在给每一个人安排房间,一个房间只能被一个人拥有。
问是否存在方案满足条件。
如果不存在,输出:Let's search for another office.
如果存在多种方案,输出:Ask Shiftman for help.
否则输出:Perfect! 并在第二行输出 $n$ 个数,第 $i$ 个数表示给第 $i$ 个人分配的房间编号。
题解
首先我们不考虑多种解的情况。
做法是个简单贪心。
我们将房间按照 $a_i$ 升序排序。
将人的需求按照 $L_i$ 升序排序。
然后从左到右依次处理每一个房间。
对于房间 $i$ ,我们从 $L$ 比他小的所有还没有被匹配的人中找到 $R_j$ 最小的(这个可以用一个堆来实现)。
如果 $R_j<a_i$ 那么由于未匹配的房间中最小的就是 $a_i$,所以这个人一定无法匹配了,所以无解。
否则让房间 $i$ 匹配第 $j$ 个人。显然让 $R_i$ 尽量小的先匹配时最优的。
这样可以得到一组解。
然后我们考虑如何判断是否多解。
假设我们已经有了一个解。
则,当且仅当下面的条件满足时,存在多解。
条件: 存在两个人,选择的房间都在他们两个人都可以接受的范围内。
于是我们要考虑如何来搞这个。
考虑对于当前人选择的当前房间。我们找到满足“选择的房间比当前房间小的,可以接受的区间比当前房间大的”人中选择的房间尽量大的,判断这两个人的房间是否可以交换。如果有解,并至少存在一组这样的人,那么为多解。这个东西显然可以再用个堆搞定。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int n,a[N],b[N];
struct Node{
int a,id;
}v[N];
struct Seg{
int L,R,id;
Seg(){}
Seg(int _L,int _R){L=_L,R=_R;}
friend bool operator < (Seg a,Seg b){
return a.R>b.R;
}
}s[N];
int res[N];
bool cmpL(Seg a,Seg b){return a.L<b.L;}
bool cmpid(Seg a,Seg b){return a.id<b.id;}
bool cmpa(Node a,Node b){return a.a<b.a;}
priority_queue <Seg> Q,Q2;
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&v[i].a),v[i].id=i;
sort(v+1,v+n+1,cmpa);
v[0].a=0,v[n+1].a=1e9+1;
for (int i=0;i<=n+1;i++)
a[i]=v[i].a,b[n+1-i]=1e9+1-v[i].a;
for (int i=1;i<=n;i++){
scanf("%d%d",&s[i].L,&s[i].R);
s[i].id=i;
s[i].L=lower_bound(a,a+n+2,s[i].L)-a;
s[i].R=n+1-(lower_bound(b,b+n+2,1e9+1-s[i].R)-b);
// printf("%d %d\n",s[i].L,s[i].R);
}
while (!Q.empty())
Q.pop();
while (!Q2.empty())
Q2.pop();
sort(s+1,s+n+1,cmpL);
bool flag=0;
for (int i=1,j=1;i<=n;i++){
while (j<=n&&s[j].L<=i)
Q.push(s[j++]);
if (Q.empty()){
puts("Let's search for another office.");
return 0;
}
Seg now=Q.top();
Q.pop();
if (now.R<i){
puts("Let's search for another office.");
return 0;
}
res[now.id]=v[i].id;
while (!Q2.empty()){
Seg Now=Q2.top();
if (Now.L<i){
Q2.pop();
continue;
}
if (now.L<=n-Now.R)
flag=1;
break;
}
Q2.push(Seg(now.R,n-i));
}
if (flag){
puts("Ask Shiftman for help.");
return 0;
}
puts("Perfect!");
for (int i=1;i<=n;i++)
printf("%d ",res[i]);
return 0;
}