题目内容:
Description
A经常会收到很多的定单。定单的内容为在第a天到第b天**团队将要在A的公司狂欢(包括第a天与第b天)。一旦接受了某一个定单,A公司就必须在第a天到第b天为该团队提供娱乐服务,中途不能取消服务。要如何安排才能使得接受的定单最多呢?
现在告诉你A公司最多能同时服务的的团队数目以及收到的所有定单,求出可以接受的定单的最大值。
Input
文件的第一行包含一个整数T,表示数据组数。
对于每组数据,第一行包含两个整数n和m,分别表示收到的定单数和公司能同时服务的团队数。接下来n行每行包含两个整数a和b,表示一个定单的内容:某个团队将在第a天与第b天之间在A公司进行狂欢。
Output
对于每组数据输出一行。该行仅包含一个整数,表示最多能接受的定单数。
题解:看到题目,我们知道这是一道高级版的线段覆盖,想法:贪心。
我们可以从左往右做,这样的话,左边的影响处理好了,对于某一个地方超过了m,我们这些之中右区间最大的删去,因为它的影响最大,而它们对左边的影响是一致的,所以删去右区间最大的就可以了。 复杂度就是(n*log(n)) (删去的右区间最大的删法,我们可以用一个堆来维护加进去的订单,这样每一个订单进入一个堆一次,最多出去一次)
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1E5+20;
bool h[N];
struct com{
int a,b,c;
bool operator < (const com & x)const{
return b<x.b;
}
bool operator >(const com &x) const{
return b>x.b;
}
}a[N];
bool cmp(com x,com y){
return x.a<y.a||(x.a==y.a&&x.b<y.b);
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].a,&a[i].b),h[i]=0;
if(a[i].a>a[i].b){
int t=a[i].a; a[i].a=a[i].b; a[i].b=t;
}
}
sort(a+1,a+n+1,cmp);//将订单按左区间排序,一个个处理
for(int i=1;i<=n;i++) a[i].c=i;
int size=0; int size1=0; int k=1;
priority_queue<com>Q;
priority_queue<com,vector<com>,greater<com> > Q1;
//Q记录大根堆,即最不优的那份订单,Q1记录之前的订单中和之后订单不冲突为优先的堆,即以右区间为关键字的小根堆。
for(int i=1;i<=n;i++){
int j=i;
while(a[j].a==a[i].a){
Q.push(a[j]); size++;
Q1.push(a[j]);
h[j]=1; j++;
}
for(com p=Q1.top();p.b<a[i].a;Q1.pop(),p=Q1.top()){
if(h[p.c]) size1++;//计算有多少个和之后的没有冲突的订单,用size1记录,size记录有多少分订单目前打算要做。
}
i=j-1;
while(size-size1>m){
com jk=Q.top();
h[jk.c]=0;
Q.pop(); size--;
}
}
printf("%d\n",size);
}
}