传送门:点击打开链接
题意:有n个小岛,每一个小岛是直线型的,他们不相互相交,第i个小岛所占的区间是[li, ri],而且, ri < li+1 对于所有的 1 ≤ i ≤ n-1。现在要将相邻的小岛用桥连接起来。现在有一条桥的长度是a,第i个岛和第i+1个岛能够连接的条件是,存在x,y使得 li ≤ x ≤ ri, li+1 ≤ y ≤ ri+1 且 y - x = a成立。
现在有m条桥,每条桥最多被使用一次,问能否把这些岛连接起来。
样例解释:在这个样例中,把第2条桥两个端点放在3和8,把第三条桥两个端点放在7和10,把第一条桥的端点放在10和14。
思路:很明显能转换成,问,m个点是否能把区间是否覆盖,一个店只能覆盖一个区间的问题。
这种题通常都是把区间按照右端点从小到大排序,右端点相等时左区间小的在前。
然后,我们用multiset来维护点,每次对区间考虑的时候,优先考虑区间里面最靠左端的点来覆盖这个区间。
很容易证明这种方式是正确的。
通常要排序区间的题都是按照右区间来排序,应该习惯这种思维。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int n, m;
struct Seg {
LL l, r;
bool operator<(const Seg &P)const {
if(r == P.r) return l < P.l;
return r < P.r;
}
} S[MX];
LL L[MX], R[MX];
multiset<LL>P;
bool solve() {
int c = 1;
for(int i = 1; i <= n - 1; i++) {
multiset<LL>::iterator it = P.lower_bound(S[i].l);
if(it == P.end() || *it > S[i].r) return false;
P.erase(it);
}
return true;
}
int main() {
//FIN;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%I64d%I64d", &L[i], &R[i]);
}
for(int i = 1; i <= n - 1; i++) {
S[i].l = L[i + 1] - R[i] + 1;
S[i].r = R[i + 1] - L[i] + 1;
}
for(int i = 1; i <= m; i++) {
LL t; scanf("%I64d", &t); t++;
P.insert(t);
}
sort(S + 1, S + n);
printf("%s\n", solve() ? "YES" : "NO");
return 0;
}