CF555B Case of Fugitive

题目大意

  有一些不相交线段和一些桥,桥可以架在两个相邻的线段上。求现有的桥是否可以使所有线段连通。

题解

  在两个线段上架桥,桥的长度在一个范围内,相当于一个长度的区间,一个桥只有一个长度,相当于一个长度的。这就转化成了点匹配区间问题。

  点匹配区间问题我们在贪心(POJ3614)那里学了,把所有区间按照左端点从大到小排序,把点按照位置从大到小排序,每次总是把最右侧区间与在该区间内的最右端点匹配。问题是:如何满足可以随时删除点,且可以快速找到该区间内的最右端点呢?用key值为点的长度递减的multiset的delete和lower_bound函数可以轻松解决。注意delete时传的参数时迭代器(指针),而不是值,否则一删就把重合的点全删了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
using namespace std;

const int MAX_LAND = 200010, MAX_BRIDGE = 200010;
int TotLand, TotLenRange, TotBridge;
int Ans[MAX_BRIDGE];

struct Bridge
{
    long long Len;
    int OrgP;

    bool operator < (const Bridge& a) const
    {
        return Len > a.Len;
    }
}_bridges[MAX_BRIDGE];

struct Cmp
{
    bool operator () (const Bridge& a, const Bridge& b)
    {
        return a.Len < b.Len;
    }
};

struct Land
{
    long long L, R;

    bool operator < (const Land& a) const
    {
        return L < a.L;
    }
}_lands[MAX_LAND];

struct LenRange
{
    long long L, R;
    int OrgL;

    bool operator < (const LenRange& a) const
    {
        return L > a.L;
    }
}_lenRanges[MAX_LAND];

void Read()
{
    scanf("%d%d", &TotLand, &TotBridge);
    TotLenRange = TotLand - 1;
    for (int i = 1; i <= TotLand; i++)
        scanf("%lld%lld", &_lands[i].L, &_lands[i].R);
    for (int i = 1; i <= TotBridge; i++)
        scanf("%lld", &_bridges[i].Len);
}

void Init()
{
    for (int i = 1; i <= TotBridge; i++)
        _bridges[i].OrgP = i;
    sort(_lands + 1, _lands + TotLand + 1);
    for (int i = 1; i <= TotLand - 1; i++)
    {
        _lenRanges[i].L = _lands[i + 1].L - _lands[i].R;
        _lenRanges[i].R = _lands[i + 1].R - _lands[i].L;
        _lenRanges[i].OrgL = i;
    }
    sort(_lenRanges + 1, _lenRanges + TotLenRange + 1);
}

void Solve()
{
    static multiset<Bridge> tree;
    for (int i = 1; i <= TotBridge; i++)
        tree.insert(_bridges[i]);
    for (int i = 1; i <= TotLenRange; i++)
    {
        Bridge temp;
        temp.Len = _lenRanges[i].R;
        multiset<Bridge>::iterator it = tree.lower_bound(temp);
        if (it == tree.end() || it->Len <_lenRanges[i].L )
        {
            printf("No\n");
            return;
        }
        Ans[_lenRanges[i].OrgL] = it->OrgP;
        tree.erase(it);
    }
    printf("Yes\n");
    for (int i = 1; i <= TotLand - 1; i++)
        printf("%d ", Ans[i]);
    printf("\n");
}

int main()
{
    Read();
    Init();
    Solve();
    return 0;
}

  

posted @ 2018-08-05 20:40  headboy2002  阅读(193)  评论(0编辑  收藏  举报