【BZOJ 1651】 [Usaco2006 Feb]Stall Reservations 专用牛棚(线段树,贪心)

博客围绕牛喝水问题展开,已知每头牛有特定喝水时间段且专用一个Stall,需确定满足要求的最少Stall数量。给出了题目描述、输入输出示例等,解题思路先是考虑线段树,后采用按起始点排序,用优先级队列维护结束点的贪心算法,还给出了两种解法的代码。

题目

Description

Oh those picky N (1 <= N <= 50,000) cows! They are so picky that each one will only be milked over some precise time interval A…B (1 <= A <= B <= 1,000,000), which includes both times A and B. Obviously, FJ must create a reservation system to determine which stall each cow can be assigned for her milking time. Of course, no cow will share such a private moment with other cows. Help FJ by determining: * The minimum number of stalls required in the barn so that each cow can have her private milking period * An assignment of cows to these stalls over time

有N头牛,每头牛有个喝水时间,这段时间它将专用一个Stall 现在给出每头牛的喝水时间段,问至少要多少个Stall才能满足它们的要求

Input
  • Line 1: A single integer, N

  • Lines 2…N+1: Line i+1 describes cow i’s milking interval with two space-separated integers.

Output
  • Line 1: The minimum number of stalls the barn must have.

  • Lines 2…N+1: Line i+1 describes the stall to which cow i will be assigned for her milking period.

Sample Input

5
1 10
2 4
3 6
5 8
4 7

Sample Output

4

OUTPUT DETAILS:

Here’s a graphical schedule for this output:

Time 1 2 3 4 5 6 7 8 9 10

Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>

Stall 2 … c2>>>>>> c4>>>>>>>>> … …

Stall 3 … … c3>>>>>>>>> … … … …

Stall 4 … … … c5>>>>>>>>> … … …

Other outputs using the same number of stalls are possible.

HINT

不妨试下这个数据,对于按结束点SORT,再GREEDY的做法 1 3 5 7 6 9 10 11 8 12 4 13 正确的输出应该是3

原题传送门

思路

首先看到这道题,第一想法居然是线段树。。。
把所有区间覆盖了之后求覆盖的最大值就行了。
于是,用线段树很 (jian) (nan) 的水过去了。

直到看到这句话:
。。。
。。。。。。。。。。。。。。。。。。

好吧,纯属眼瞎。。。

我们按起始点排序,用一个优先级队列(大根堆)维护结束点,然后拿新的牛跟结束时间最靠前的元素比一下,如果新的牛可以喝水,队首改为当新的牛的结束点,否则就直接往队列里新加入当前结束点,最后把队列的大小打出即可。

代码

  • 解法1:线段树
//1、线段树
#include <bits/stdc++.h>
 
using namespace std;
const int M = 1010010;
struct node {
    int l, r, w, f;
} t[4*M];
int a, b, n, aa[50010], bb[50010];
 
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1)+(x << 3)+(ch ^ 48);
        ch = getchar();
    }
    return x*f;
}
 
void build(int k, int L, int R) {
    t[k].l = L, t[k].r = R;
    if (t[k].l == t[k].r) return ;
    int m = (L + R) / 2;
    build(k*2, L, m);
    build(k*2+1, m+1, R);
}
 
inline void down(int k) {
    t[k*2].f += t[k].f;
    t[k*2+1].f += t[k].f;
    t[k*2].w += t[k].f;
    t[k*2+1].w += t[k].f;
    t[k].f = 0;
}
 
void change_interval(int k) {
    if (t[k].l >= a && t[k].r <= b) {
        t[k].w++, t[k].f++;
        return ;
    }
    if(t[k].f) down(k);
    int m=(t[k].l+t[k].r)/2;
    if (a <= m) change_interval(k*2);
    if (b > m) change_interval(k*2+1);
    t[k].w = max(t[k*2].w, t[k*2+1].w);
}
 
int main() {
    ios::sync_with_stdio(false);
    int m = read(), n = -10;
    for (int i = 1; i <= m; i++)
        aa[i] = read(), bb[i] = read(), n = max(bb[i], n);
	build(1, 1, n);
	for (int i = 1; i <= m; i++)
		a = aa[i], b = bb[i], change_interval(1);
    cout << t[1].w << endl;
    return 0;
}
  • 解法2:贪心
//2、贪心
#include <bits/stdc++.h>

using namespace std;
struct node {
	int s, e;
} a[50010];
priority_queue <int, vector<int>,greater<int> > q;

inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1)+(x << 3)+(ch ^ 48);
        ch = getchar();
    }
    return x*f;
}

bool cmp(const node &a, const node &b) {
	return a.s < b.s;
}

int main() {
	ios::sync_with_stdio(false);
	int n = read();
	for (int i = 1; i <= n; i++)
		a[i].s = read(), a[i].e = read();
	sort(a+1, a+1+n, cmp);
	for (int i = 1; i <= n; i++) {
		if (q.size() == 0) {q.push(a[i].e); continue;}
		if (q.top() < a[i].s) q.pop();
		q.push(a[i].e);
	}
	cout << q.size() << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值