贪心 51Nod1460 连接小岛

来源:互联网 发布:电子阅览室软件 编辑:程序博客网 时间:2024/04/28 06:35

传送门:点击打开链接

题意:有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;}


0 0
原创粉丝点击