NOIP2012借教室

发布于 2019-10-30  473 次阅读


题目描述

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

面对海量租借教室的信息,我们自然希望编程解决这个问题。

我们需要处理接下来$n$天的借教室信息,其中第ii天学校有$r_i$
​ 个教室可供租借。共有$m$份订单,每份订单用三个正整数描述,分别为$d_j,s_j,t_j$ ,表示某租借者需要从第$s_j$天到第$t_j$天租借教室(包括第$s_j$天和第$t_j$天),每天需要租借$d_j$个教室。

我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供$d_j$个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第$s_j$天到第$t_j$天中有至少一天剩余的教室数量不足$d_j$个。

现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

输入格式
第一行包含两个正整数$n,m$,表示天数和订单的数量。

第二行包含$n$个正整数,其中第$i$个数为$r_i$
​ ,表示第$i$天可用于租借的教室数量。

接下来有$m$行,每行包含三个正整数$d_j,s_j,t_j$,表示租借的数量,租借开始、结束分别在第几天。

每行相邻的两个数之间均用一个空格隔开。天数与订单均用从$1$开始的整数编号。

输出格式
如果所有订单均可满足,则输出只有一行,包含一个整数$0$。否则(订单无法完全满足)

输出两行,第一行输出一个负整数$-1$,第二行输出需要修改订单的申请人编号。

题解

题目看了一半的时候以为是二分答案,后来。。。。

这不就是个线段树么

题意很明确,让你维护一个区间,每次给这段区间加上1,之后判断它的值是否超出了给定的界限。

这样维护很麻烦,我们可以逆向操作。

先给线段树赋上最大租借的教室数,之后区间减一,一旦有一个数小于零的话,说明教室不够了,输出便可。

代码(这次线段树写的比较毒瘤)

#include <iostream>

using namespace std;

namespace my
{
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define maxn 2000006

class segmentTree
{
public:
    void build(int l, int r, int rt);
    void modify(int l, int r, int rt, int fl, int fr, int x);
    inline int find();

private:
    inline int min(int x, int y);
    inline void update(int rt);
    inline void add(int l, int r, int rt, int x);
    inline void push(int l, int r, int rt);
    int z[maxn], tag[maxn];
};

inline int segmentTree::min(int x, int y)
{
    return x > y ? y : x;
}

void segmentTree::build(int l, int r, int rt)
{
    if(l == r)
    {
        cin >> z[rt];
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    update(rt);
}

inline void segmentTree::update(int rt)
{
    z[rt] = min(z[rt << 1], z[rt << 1 | 1]);
}

void segmentTree::modify(int l, int r, int rt, int fl, int fr, int x)
{
    if(l == fl and fr == r)
    {
        add(l, r, rt, x);
        return;
    }
    push(l, r, rt);
    int mid = (l + r) >> 1;
    if(fl <= mid)
    {
        if(fr > mid) modify(lson, fl, mid, x), modify(rson, mid + 1, fr, x);
        else modify(lson, fl, fr, x);
    }
    else
        modify(rson, fl, fr, x);
    update(rt);
}

inline int segmentTree::find()
{
    return z[1];
}

inline void segmentTree::add(int l, int r, int rt, int x)
{
    z[rt] -= x;
    tag[rt] += x;
}

inline void segmentTree::push(int l, int r, int rt)
{
    if(tag[rt])
    {
        int mid = (l + r) >> 1;
        add(lson, tag[rt]);
        add(rson, tag[rt]);
        tag[rt] = 0;
    }
}

#undef lson
#undef rson
#undef maxn
}

my::segmentTree t;

int n, m, d, l, r;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m;

    t.build(1, n, 1);

    for(register int i = 1; i <= m ;i++)
    {
        cin >> d >> l >> r;
        t.modify(1, n, 1, l, r, d);
        if(t.find() < 0)
        {
            cout << "-1\n" << i << endl;
            return 0;
        }
    }
    cout << "0";
    return 0;
}

THE END