P1937 [USACO10MAR]Barn Allocation G

发布时间 2023-05-20 16:38:23作者: cspD-C

Barn Allocation G

题目描述

农夫约翰最近开了一个新的牲口棚屋,并且现在接受来自奶牛的分配畜栏请求因为其中的一些畜栏有更好风景。

畜栏包括N个畜栏(1 ≤ N ≤ 100,000),方便起见,我们把它们编号为1..N,畜栏i能容纳Ci只牛(1 ≤ Ci ≤ 100,000),第i只牛需要连续编号畜栏(从Ai到Bi)来漫步其中,

(1 ≤ Ai ≤ N; Ai ≤ Bi ≤ N),换言之,这只牛想要在编号范围为Ai..Bi的畜栏漫步(所有它想要畜栏必须实施为它空出位置来供它散步)

给出M个畜栏分配请求(1 ≤ M ≤ 100,000),回答最多能满足多少只牛的要求(不增加另外畜栏)

考虑以下例子:

畜栏号:    1   2   3   4   5
           +---+---+---+---+---+
容纳空间:  | 1 | 3 | 2 | 1 | 3 |  
           +---+---+---+---+---+
Cow 1       XXXXXXXXXXX             (1, 3)
Cow 2           XXXXXXXXXXXXXXX     (2, 5)
Cow 3           XXXXXXX             (2, 3)
Cow 4                   XXXXXXX     (4, 5)

约翰显然不能满足所有的牛,因为畜栏3,4请求太多了

经过试验,我们发现,我们能满足牛1,3,4需要,所以这组数据答案为3

输入格式

第一行包括两个以空格隔开的正整数:N,M

第二行到第N+1行:第i+1行包括一个整数:Ci

第N+2到第N+M+1行:第i+N+1 包括两个整数Ai、Bi

输出格式

仅一行:能满足的最大需要

样例 #1

样例输入 #1

5 4
1
3
2
1
3
1 3
2 5
2 3
4 5

样例输出 #1

3

分析:

区间贪心 + 线段树维护区间最小值
贪心方法与最大不相交区间数量相同,只是每个区间不是固定只能放一个线段,贪心选择后,在线段树区间修改

实现:

#include <bits/stdc++.h>
using namespace std;
#define mst(x, y) memset(x, y, sizeof x)
#define endl '\n'
#define INF LONG_LONG_MAX
#define int long long
#define Lson u << 1, l, mid
#define Rson u << 1 | 1, mid + 1, r
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200010, MOD = 1e9 + 7;
const double EPS = 1e-6;
typedef pair<int, int> PII;
int T;
int n, m;
int res;
int a[N];
struct P
{
    int l, r;
} p[N];
struct Node
{
    int l, r;
    int minv;
    int lz;
} tr[N << 2];
bool cmp(P a, P b)
{
    return a.r < b.r;
}
void pushup(Node &u, Node &l, Node &r)
{
    u.minv = min(l.minv, r.minv);
}
void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void pushdown(int u)
{
    if (tr[u].lz)
    {
        tr[u << 1].minv += tr[u].lz;
        tr[u << 1 | 1].minv += tr[u].lz;
        tr[u << 1].lz += tr[u].lz;
        tr[u << 1 | 1].lz += tr[u].lz;
        tr[u].lz = 0;
    }
}
void build(int u, int l, int r)
{
    if (l == r)
        tr[u] = {r, r, a[l]};
    else
    {
        tr[u] = {l, r, INF};
        int mid = l + r >> 1;
        build(Lson), build(Rson);
        pushup(u);
    }
}
int query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].minv;
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        int res = INF;
        if (l <= mid)
            res = query(u << 1, l, r);
        if (r > mid)
            res = min(res, query(u << 1 | 1, l, r));
        return res;
    }
}
void modify(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].minv--;
        tr[u].lz--;
    }
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid)
            modify(u << 1, l, r);
        if (r > mid)
            modify(u << 1 | 1, l, r);
        pushup(u);
    }
}
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= m; i++)
        cin >> p[i].l >> p[i].r;

    sort(p + 1, p + 1 + m, cmp);
    build(1, 1, n);

    for (int i = 1; i <= m; i++)
    {
        if (query(1, p[i].l, p[i].r) <= 0)
            continue;
        else
        {
            modify(1, p[i].l, p[i].r);
            res++;
        }
    }

    cout << res << endl;
}
signed main()
{
    FAST;
    T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}