题意:按顺序给出多个互不相交的区间(表示一些小岛),和一些可以连接区间的桥,每个桥有固定的长度。区间和桥的数量都是2*10^5。
两个相邻的小岛之间的桥的长度必须小于等于最远点距离,大于等于最近点距离。问是否能用这些桥把所有小岛连接在一起。
分析:区间排序问题。但是这个题里需要排序的区间并不是题里直接给出的小岛。而是要先把桥从小到大排序。
然后对于每两个相邻小岛,在这个桥的序列里都有一个区间内的桥是可以用来连接这两个小岛的。
对于每两个相邻小岛,求出其对应的桥区间,然后把这些区间排序。
排序规则是先按右边缘从小到大,右边相同的按左边缘从小到大。
排序后依次在这些区间里选取对应的桥,每次选取区间内最小的未被使用的桥即可。
至于排序的时候为什么先又后左,是因为不同区间对于左侧的桥资源的迫切程度,肯定是右边缘越偏左,需求越迫切。
所以应当优先将左侧的资源分配给右边缘比较偏左的区间。
要求一个数字集合里面位于一个区间内的最小值,可以用lower_bound函数。
而依次删除使用过的桥,可以用multiset(它有lower_bound这个成员函数)。
当想要使用包含三个值的结构体的时候,可以用两个pair嵌套。
#include <cstdio> #include <iostream> #include <algorithm> #include <set> #include <vector> using namespace std; #define d(x) const int MAX_N = 2 * (int)(1e5) + 10; pair<long long, long long> island[MAX_N]; int bridge_num; int island_num; int ans[MAX_N]; pair<long long, pair<long long, int> > range[MAX_N]; multiset<pair<long long, int> > bridge; bool ok() { for (int i = 0; i < island_num - 1; i++) { long long l = range[i].second.first; long long r = range[i].first; __typeof(bridge.begin()) it = bridge.lower_bound(make_pair(l, -1)); if (it == bridge.end()) return false; if ((*it).first > r) return false; ans[range[i].second.second] = it->second; bridge.erase(it); } return true; } void input() { scanf("%d%d", &island_num, &bridge_num); for (int i = 0; i < island_num; i++) { long long a, b; cin >> a >> b; island[i] = make_pair(a, b); } for (int i = 0; i < bridge_num; i++) { long long a; cin >> a; bridge.insert(make_pair(a, i)); } } int main() { input(); for (int i = 0; i < island_num - 1; i++) { long long min_len = island[i + 1].first - island[i].second; long long max_len = island[i + 1].second - island[i].first; range[i] = make_pair(max_len, make_pair(min_len, i)); } sort(range, range + island_num - 1); if (ok()) { puts("Yes"); for (int i = 0; i < island_num - 1; i++) { if (i != 0) putchar(' '); printf("%d", ans[i] + 1); } putchar(' '); } else puts("No"); return 0; }