贪心 51Nod1460 连接小岛

传送门:点击打开链接

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值