[CSP-S 2021] 廊桥分配【set】【二分】

>Link

luogu P7913


>Description

[CSP-S 2021] 廊桥分配【set】【二分】_第1张图片
n ≤ 1 0 5 n\le 10^5 n105


>解题思路

跟考场上的想法一样,不过那时候没学set,不知道怎么实现边删数边二分,然后就打了一个好麻烦的堆然后挂了TT set大法好(虽然说也有set以外的方法
根据题意,想到一种方法,先处理出 f i f_i fi f f i ff_i ffi,分别表示国内/国际分到 i i i 个廊桥,停靠在廊桥的飞机数量
答案就为 m a x 1 ≤ i ≤ n f i + f f n − 1 max_{1\le i\le n}f_i+ff_{n-1} max1infi+ffn1
然后转换题意,我们每新加一个廊桥,就是第一个原来没有廊桥停靠的飞机来停,它离开后第一个来到且也是原来没有廊桥停靠的飞机来停(先到先得)
然后可以直接用set保存目前没有廊桥停靠的飞机,一开始把所有区间转换成pair加进来,处理 f f f f f ff ff 时就是不断找出“子序列”并删除,找的过程可以用二分实现


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#define N 100010
using namespace std;

set<pair <int, int> > st;
int n, m1, m2, f[N], ff[N], ans;

int main()
{
//	freopen ("P7913_9.in", "r", stdin);
	scanf ("%d%d%d", &n, &m1, &m2);
	int l, r;
	for (int i = 1; i <= m1; i++)
	{
		scanf ("%d%d", &l, &r);
		st.insert (make_pair (l, r)); 
	}
	set<pair <int, int> >::iterator now;
	for (int i = 1; i <= n; i++)
	{
		f[i] = f[i - 1];
		now = st.begin();
		while (now != st.end())
		{
			f[i]++;
			r = now -> second;
			st.erase (now);
			now = st.lower_bound (make_pair (r + 1, 0));
		}
	}
	st.clear();
	for (int i = 1; i <= m2; i++)
	{
		scanf ("%d%d", &l, &r);
		st.insert (make_pair (l, r)); 
	}
	for (int i = 1; i <= n; i++)
	{
		ff[i] = ff[i - 1];
		now = st.begin();
		while (now != st.end())
		{
			ff[i]++;
			r = now -> second;
			st.erase (now);
			now = st.lower_bound (make_pair (r + 1, 0)); 
		}
	}
	for (int i = 0; i <= n; i++)
	  ans = max (ans, f[i] + ff[n - i]);
	printf ("%d", ans);
	return 0;
}

你可能感兴趣的:(其他,二分,宽度优先,算法,leetcode)