有 NN 头牛在畜栏中吃草。
每个畜栏在同一时间段只能提供给一头牛吃草,所以可能会需要多个畜栏。
给定 NN 头牛和每头牛开始吃草的时间 AA 以及结束吃草的时间 BB,每头牛在 [A,B][A,B] 这一时间段内都会一直吃草。
当两头牛的吃草区间存在交集时(包括端点),这两头牛不能被安排在同一个畜栏吃草。
求需要的最小畜栏数目和每头牛对应的畜栏方案。
输入格式
第 11 行:输入一个整数 NN。
第 2..N+12..N+1 行:第 i+1i+1 行输入第 ii 头牛的开始吃草时间 AA 以及结束吃草时间 BB,数之间用空格隔开。
输出格式
第 11 行:输入一个整数,代表所需最小畜栏数。
第 2..N+12..N+1 行:第 i+1i+1 行输入第 ii 头牛被安排到的畜栏编号,编号是从 11 开始的 连续 整数,只要方案合法即可。
数据范围
1≤N≤500001≤N≤50000,
1≤A,B≤10000001≤A,B≤1000000输入样例:
5 1 10 2 4 3 6 5 8 4 7
输出样例:
4 1 2 3 2 4
解题思路:
1:先将吃草区间按左端点排序
2:若当前枚举的区间有交集,用小根堆记录当前最后一头牛的吃草结束区间;
3:若无交集,说明可以从之前枚举过的区间中选择右端点的最小值;
为什么选择最小值呢?
因为如果选择大于最小值的值,则它的右交点可能与当前枚举的区间有交集,使得
答案偏大,因此必须选择最小值,即小根堆的堆顶元素
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define x first
#define y second
using namespace std;
const int N = 50010;
typedef pair<int, int> PII;
int n;
int id[N];//id[i]为第i头牛所在的畜栏为id[i];
pair<PII, int> cows[N];//三个变量分别为吃草开始的时间,吃草结束的时间,以及当前牛是第几个牛
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d %d", &l, &r);
cows[i].y = i;
cows[i].x.x = l;
cows[i].x.y = r;
}
sort(cows, cows + n);
priority_queue<PII, vector<PII>, greater<PII>> heap;
for (int i = 0; i < n; i ++ )
{
if (heap.empty() || heap.top().x >= cows[i].x.x)//若当前堆中为空,或者枚举过的区间的最小值大于等于
{//当前区间的左端点,则需要新加一个畜栏,即将次畜栏加入堆中
PII stall = {cows[i].x.y, heap.size()};
id[cows[i].y] = stall.y;
heap.push(stall);
}
else//说明枚举过的区间的右端点的最小值大于当前左区间最小值,即安排进以前枚举过的右端点最小值的畜栏
{
PII stall = heap.top();//将右端点的最小值拿出
heap.pop();//删去最小值;
stall.x = cows[i].x.y;//更新右端点的最小值
id[cows[i].y] = stall.y;
heap.push(stall);
}
}
cout << heap.size() << endl;//heap.size()里面即存了可以选择的畜栏
for (int i = 0; i < n; i ++ ) printf("%d\n", id[i] + 1);//因为heap.size()从0开始所以每个树要加一
return 0;
}