[Usaco2010 Mar]balloc 农场分配

32 篇文章 0 订阅
24 篇文章 0 订阅


Farmer John最近新建立了一个农场,并且正在接受奶牛的畜栏分配请求,有些
畜栏会看到农场美妙的风景。:)

农场由N (1 <= N <= 100,000) 个畜栏组成,编号为1..N,畜栏i可以最多容纳C_i只奶牛
(1 <= C_i <= 100,000)。奶牛i希望得到连续的一段畜栏,表示为一段区间 (A_i,B_i) 。
这样的话奶牛可以在这段牛棚里面转悠。(当然,这段畜栏必须要有足够的空间)

给出M (1 <= M <= 100,000) 个请求,请求出不超过畜栏承载量的情况下,最多可以满足的请求数。



具体做法就是

对请求,按照r关键字递增排序,然后r相同就按照l递减排序。

总的来讲就是优先截止早的区间,相同的话就优先区间长度小的区间。

然后一个一个请求往里塞,就是线段树操作了。能塞的塞进去,不能的就continue

每个位置有个权值代表剩余多少个空位。

对于一个区间覆盖时就看区间最小值是否大于0.

然后区间更新即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <map>
#include <sstream>
#include <queue>
#include <vector>
#define MAXN 100005
#define MAXM 211111
#define eps 1e-8
#define INF 50000001
#define lch(x) x<<1
#define rch(x) x<<1|1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int mi[MAXN * 4];
int cover[MAXN * 4];
struct node
{
    int l, r;
}q[MAXN];
bool cmp(node x, node y)
{
    if(x.r != y.r) return x.r < y.r;
    return x.l > y.l;
}
int a[MAXN];
int n, m;
void up(int rt)
{
    mi[rt] = min(mi[lch(rt)], mi[rch(rt)]);
}
void down(int rt)
{
    if(cover[rt])
    {
        cover[lch(rt)] += cover[rt];
        cover[rch(rt)] += cover[rt];
        mi[lch(rt)] -= cover[rt];
        mi[rch(rt)] -= cover[rt];
        cover[rt] = 0;
    }
}
void build(int l, int r, int rt)
{
    if(l == r)
    {
        mi[rt] = a[l];
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    up(rt);
}
int check(int L, int R, int l, int r, int rt)
{
    if(L <= l && R >= r) return mi[rt];
    down(rt);
    int m = (l + r) >> 1;
    int mi = INF;
    if(L <= m) mi = min(mi, check(L, R, lson));
    if(R > m) mi = min(mi, check(L, R, rson));
    return mi;
}
void update(int L, int R, int l, int r, int rt)
{
    if(L <= l && R >= r)
    {
        cover[rt] += 1;
        mi[rt] -= 1;
        return;
    }
    down(rt);
    int m = (l + r) >> 1;
    if(L <= m) update(L, R, lson);
    if(R > m) update(L, R, rson);
    up(rt);
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    build(1, n, 1);
    for(int i = 0; i < m; i++) scanf("%d%d", &q[i].l, &q[i].r);
    sort(q, q + m, cmp);
    int ans = 0;
    for(int i = 0; i < m; i++)
    {
        if(check(q[i].l, q[i].r, 1, n, 1) > 0) ans++, update(q[i].l, q[i].r, 1, n, 1);
    }
    printf("%d\n", ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值