洛谷P7913 廊桥分配

题目描述

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

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

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

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

输入格式

输入的第一行,包含三个正整数 n, m_1, m_2n,m1​,m2​,分别表示廊桥的个数、国内航班飞机的数量、国际航班飞机的数量。

接下来 m_1m1​ 行,是国内航班的信息,第 ii 行包含两个正整数 a_{1, i}, b_{1, i}a1,i​,b1,i​,分别表示一架国内航班飞机的抵达、离开时刻。

接下来 m_2m2​ 行,是国际航班的信息,第 ii 行包含两个正整数 a_{2, i}, b_{2, i}a2,i​,b2,i​,分别表示一架国际航班飞机的抵达、离开时刻。

每行的多个整数由空格分隔。

输出格式

输出一个正整数,表示能够停靠廊桥的飞机数量的最大值。

输入输出样例

输入 #1复制

3 5 4
1 5
3 8
6 10
9 14
13 18
2 11
4 15
7 17
12 16

输出 #1复制

7

输入 #2复制

2 4 6
20 30
40 50
21 22
41 42
1 19
2 18
3 4
5 6
7 8
9 10

输出 #2复制

4

说明/提示

【样例解释 #1】

在图中,我们用抵达、离开时刻的数对来代表一架飞机,如 (1, 5)(1,5) 表示时刻 11 抵达、时刻 55 离开的飞机;用 \surd√ 表示该飞机停靠在廊桥,用 \times× 表示该飞机停靠在远机位。

我们以表格中阴影部分的计算方式为例,说明该表的含义。在这一部分中,国际区有 22 个廊桥,44 架国际航班飞机依如下次序抵达:

  1. 首先 (2, 11)(2,11) 在时刻 22 抵达,停靠在廊桥。
  2. 然后 (4, 15)(4,15) 在时刻 44 抵达,停靠在另一个廊桥。
  3. 接着 (7, 17)(7,17) 在时刻 77 抵达,这时前 22 架飞机都还没离开、都还占用着廊桥,而国际区只有 22 个廊桥,所以只能停靠远机位。
  4. 最后 (12, 16)(12,16) 在时刻 1212 抵达,这时 (2, 11)(2,11) 这架飞机已经离开,所以有 11 个空闲的廊桥,该飞机可以停靠在廊桥。

根据表格中的计算结果,当国内区分配 22 个廊桥、国际区分配 11 个廊桥时,停靠廊桥的飞机数量最多,一共 77 架。

【样例解释 #2】

当国内区分配 22 个廊桥、国际区分配 00 个廊桥时,停靠廊桥的飞机数量最多,一共 44 架,即所有的国内航班飞机都能停靠在廊桥。

需要注意的是,本题中廊桥的使用遵循“先到先得”的原则,如果国际区只有 11 个廊桥,那么将被飞机 (1, 19)(1,19) 占用,而不会被 (3, 4)(3,4)、(5, 6)(5,6)、(7, 8)(7,8)、(9, 10)(9,10) 这 44 架飞机先后使用。

【数据范围】

对于 20 \%20% 的数据,n \le 100n≤100,m_1 + m_2 \le 100m1​+m2​≤100。
对于 40 \%40% 的数据,n \le 5000n≤5000,m_1 + m_2 \le 5000m1​+m2​≤5000。
对于 100 \%100% 的数据,1 \le n \le {10}^51≤n≤105,m_1, m_2 \ge 1m1​,m2​≥1,m_1 + m_2 \le {10}^5m1​+m2​≤105,所有 a_{1, i}, b_{1, i}, a_{2, i}, b_{2, i}a1,i​,b1,i​,a2,i​,b2,i​ 为数值不超过 {10}^8108 的互不相同的正整数,且保证对于每个 i \in [1, m_1]i∈[1,m1​],都有 a_{1, i} < b_{1, i}a1,i​<b1,i​,以及对于每个 i \in [1, m_2]i∈[1,m2​],都有 a_{2, i} < b_{2, i}a2,i​<b2,i​。

上代码:

#include <bits/stdc++.h>

using namespace std;

const int Maxn = 1e5 + 5;

struct e {
	int st, ed;
} a[Maxn];
bool cmp(e x, e y) {
	return x.st < y.st;
}

std::priority_queue<int> hp_id;
std::priority_queue<std::pair<int, int> > hp_ed; 

int n, m1, m2, ca[Maxn], cb[Maxn];

int main() {
	scanf("%d%d%d", &n, &m1, &m2);
	for(int i = 1; i <= m1; ++i) scanf("%d%d", &a[i].st, &a[i].ed);
	std::sort(a + 1, a + m1 + 1, cmp);
	for(int i = 1; i <= n; ++i) hp_id.push(-i);
	for(int i = 1; i <= m1; ++i) {
		if(!hp_ed.empty()) {
            while(-hp_ed.top().first < a[i].st) {
                hp_id.push(-hp_ed.top().second), hp_ed.pop();
                if(hp_ed.empty()) break;
            }
        }
        if(!hp_id.empty()) {
			int x = -hp_id.top(); hp_id.pop();
			ca[x]++; hp_ed.push(std::make_pair(-a[i].ed, x));
		}
	}
    for(int i = 1; i <= n; ++i) ca[i] += ca[i - 1];
	while(!hp_ed.empty()) hp_ed.pop(); while(!hp_id.empty()) hp_id.pop();
	for(int i = 1; i <= m2; ++i) scanf("%d%d", &a[i].st, &a[i].ed);
	std::sort(a + 1, a + m2 + 1, cmp);
	for(int i = 1; i <= n; ++i) hp_id.push(-i); 
	for(int i = 1; i <= m2; ++i) {
		if(!hp_ed.empty()) {
            while(-hp_ed.top().first < a[i].st) {
                hp_id.push(-hp_ed.top().second), hp_ed.pop();
                if(hp_ed.empty()) break;
            }
        }
		if(!hp_id.empty()) {
			int x = -hp_id.top(); hp_id.pop();
			cb[x]++; hp_ed.push(std::make_pair(-a[i].ed, x));
		}
	}
	for(int i = 1; i <= n; ++i) cb[i] += cb[i - 1]; 
	
	int mx_ans = 0;
	for(int i = 0; i <= n; ++i) mx_ans = std::max(mx_ans, ca[i] + cb[n - i]);
	printf("%d", mx_ans);
	
	return 0;
}

 

廊桥分配问题是指给定一座长度为n的廊桥以及m个人,每个人需要跨过廊桥到对面。廊桥每次只能让两个人同时通过,且只有两个人的速度加和不超过廊桥长度时才能通过。每个人过桥所需的时间不同,要求找到一种过桥方案使得所有人的总过桥时间最短。 该问题可以通过使用线段树的解法。首先,将n个位置看作是一棵树,每个节点对应一个位置。然后,我们将所有人按照过桥时间从小到大排序,并按照排序结果为每个节点分配一个排序编号。接下来,从左到右遍历排序后的人员列表,对于每个人,我们找到其对应的节点,并为该节点分配一个值,表示该位置可以被占用。 这样,在分配完所有人的节点后,我们得到了一个线段树,每个非叶子节点表示一个廊桥位置,叶子节点表示一个人,其父节点的值表示桥上人员的速度加和。通过遍历这颗树,可以计算出所有人过桥的最短总时间。 具体操作如下: 1. 根据所有人的过桥时间从小到大排序。 2. 为每个节点分配排序编号。 3. 初始化线段树的所有节点为空(未占用)。 4. 从左到右遍历排序后的人员列表,对于每个人: a. 找到对应的节点。 b. 判断该节点是否为空,如果为空,表示该位置可以被占用,否则找到该节点的兄弟节点(该节点的父节点的其他子节点)。 c. 将该节点或其兄弟节点标记为占用,并更新父节点的值。 5. 遍历线段树,计算所有人过桥的总时间。 使用线段树解决廊桥分配问题的时间复杂度为O(nlogn),因为排序的时间复杂度为O(nlogn),遍历人员列表的时间复杂度为O(n),遍历线段树的时间复杂度为O(nlogn)。总的空间复杂度为O(n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值