[CSP-S 2021]廊桥分配

廊桥分配

题面

当一架飞机抵达机场时,可以停靠在航站楼旁的廊桥,也可以停靠在位于机场边缘的远机位。乘客一般更期待停靠在廊桥,因为这样省去了坐摆渡车前往航站楼的周折。然而,因为廊桥的数量有限,所以这样的愿望不总是能实现。

机场分为国内区和国际区,国内航班飞机只能停靠在国内区,国际航班飞机只能停靠在国际区。一部分廊桥属于国内区,其余的廊桥属于国际区。

\(L\) 市新建了一座机场,一共有 \(n\) 个廊桥。该机场决定,廊桥的使用遵循“先到先得”的原则,即每架飞机抵达后,如果相应的区(国内/国际)还有空闲的廊桥,就停靠在廊桥,否则停靠在远机位(假设远机位的数量充足)。该机场只有一条跑道,因此不存在两架飞机同时抵达的情况。

现给定未来一段时间飞机的抵达、离开时刻,请你负责将 \(n\) 个廊桥分配给国内区和国际区,使停靠廊桥的飞机数量最多。

\(1\leq n \leq 10^5,m_1、m_2\geq 1,m_1+m_2\leq 10^5\)

\(m_1\)\(m_2\) 分别表示国内航班的数量与国际航班的数量。

分析

观察数据范围,显然我们大概需要一个 \(O(nlogn)\) 的做法,考虑怎么做。

原题面中本来附有一个表格,从表格统计的形式来看,猜测最后的答案统计是 \(O(n)\) 的,即我们需要求出分配 \(x\) 个廊桥给国内与国外能够停靠的飞机数量。

发现每个廊桥实际上相互之间不干扰,我们可以把飞机分成若干个组,每个组由同一个廊桥包办。

于是我们可以维护这样一个过程:

  • 如果存在廊桥空闲,取用编号最小的空闲廊桥(尽量少的廊桥尽量多的值,故编号要选最小)。

  • 若不存在,新开一组,增加一个廊桥。

以上过程我们可以用两个小根堆维护,一个维护目前不空闲的廊桥的状态,一个维护空闲廊桥的编号即可。

CODE

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w*=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
struct Brige{
	int t,num;
	friend bool operator < (const Brige &X,const Brige &Y ){
		return X.t>Y.t; //小根 
	}
};
struct node{ int st,ed; }A[N],B[N]; 
struct Airport{ int a,b; }dp[N],sum[N];
int n,ans;
int x,y;
priority_queue<Brige> q;
priority_queue<int,vector<int>,greater<int> > id; //小根堆,储存目前空余编号 
inline bool cmp(node a,node b) { return a.st<b.st; }
int main()
{
//	freopen("airport.in","r",stdin);
//	freopen("airport.out","w",stdout);
	n=read(),x=read(),y=read();
	for(register int i=1;i<=x;i++){
		A[i].st=read(),A[i].ed=read();
	}
	for(register int i=1;i<=y;i++){ 
		B[i].st=read(),B[i].ed=read(); 
	} 
	sort(A+1,A+x+1,cmp),sort(B+1,B+y+1,cmp); 
	int cnt=0; 
	for(register int i=1;i<=x;i++){ 
		while(q.size()){ 
			Brige now=q.top(); 
			if(now.t>A[i].st) break; 
			q.pop(); //空闲,弹出 
			id.push(now.num); //第num号桥空闲 
		}
		if(id.size()){ //有桥空闲 
			int now=id.top(); id.pop();
			dp[now].a++; //使用第now号桥飞机停泊量++ 
			q.push((Brige){A[i].ed,now});
		}
		else{ //无桥空闲 
			cnt++; //新建立一个桥
			dp[cnt].a++;
			q.push((Brige){A[i].ed,cnt});
		} 
	}
	cnt=0;
	while(!q.empty()) q.pop();
	while(!id.empty()) id.pop();
	for(register int i=1;i<=y;i++){
		while(q.size()){
			Brige now=q.top();
			if(now.t>B[i].st) break;
			q.pop(); //空闲,弹出 
			id.push(now.num); //第num号桥空闲 
		}
		if(id.size()){ //有桥空闲 
			int now=id.top(); id.pop();
			dp[now].b++; //使用第now号桥飞机停泊量++ 
			q.push((Brige){B[i].ed,now});
		}
		else{ //无桥空闲 
			cnt++; //新建立一个桥
			dp[cnt].b++;
			q.push((Brige){B[i].ed,cnt});
		} 
	}
	for(register int i=1;i<=n;i++) sum[i].a=sum[i-1].a+dp[i].a;
	for(register int i=1;i<=n;i++) sum[i].b=sum[i-1].b+dp[i].b;
	for(register int i=0;i<=n;i++){
		ans=max(ans,sum[i].a+sum[n-i].b);
	}
	printf("%d\n",ans); 
	return 0;
}
posted @ 2021-10-25 09:10  ╰⋛⋋⊱๑落叶๑⊰⋌⋚╯  阅读(396)  评论(3编辑  收藏  举报