洛谷P1937 [USACO10MAR]仓配置Barn Allocation
Farmer John recently opened up a new barn and is now accepting stall allocation requests from the cows since some of the stalls have a better view of the pastures.
The barn comprises N (1 <= N <= 100,000) stalls conveniently numbered 1..N; stall i has capacity C_i cows (1 <= C_i <= 100,000). Cow i may request a contiguous interval of stalls (A_i, B_i) in which to roam (1 <= A_i <= N; A_i <= B_i <= N), i.e., the cow would like to wander among all the stalls in the range A_i..B_i (and the stalls must always have the capacity for her to wander).
Given M (1 <= M <= 100,000) stall requests, determine the maximum number of them that can be satisfied without exceeding stall
capacities.
农夫约翰最近开了一个新的牲口棚屋,并且现在接受来自奶牛的分配畜栏请求因为其中的一些畜栏有更好风景。
畜栏包括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
输出格式:
仅一行:能满足的最大需要
输入输出样例
5 4 1 3 2 1 3 1 3 2 5 2 3 4 5
3
说明
Source: USACO 2010 March Gold
Translator: @chrome01
分析:这道题其实和借教室那道题差不多,可以考虑用线段树来维护,我们考虑一个区间是只用考虑它的最小值的,如果最小值都能满足条件,那么肯定是能够满足条件的,那么怎么样才能让题目给定的区间不重复呢?考虑贪心,我们先按照右端点从小到大排序,再按照左端点从大到小排序,这样可以保证区间之间尽量不要互相影响,最后先查询最小值,再修改就好了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int inf = 0x7ffffff; int n,m,minn[300010],flag[300010],ans; bool flag2 = false; struct node { int a,b; }e[100010]; bool cmp(node x,node y) { if (x.b != y.b) return x.b < y.b; else return x.a > y.a; } void pushup(int o) { minn[o] = min(minn[o * 2],minn[o * 2 + 1]); } void pushdown(int o) { if (flag[o]) { flag[o * 2] += flag[o]; flag[o * 2 + 1] += flag[o]; minn[o * 2] -= flag[o]; minn[o * 2 + 1] -= flag[o]; } flag[o] = 0; } void build(int l,int r,int o) { if (l == r) { scanf("%d",&minn[o]); return; } int mid = (l + r) >> 1; build(l,mid,o * 2); build(mid + 1,r,o * 2 + 1); pushup(o); } void update(int l,int r,int o,int x,int y) { if (x <= l && r <= y) { flag[o]++; minn[o]--; return; } pushdown(o); int mid = (l + r) >> 1; if (x <= mid) update(l,mid,o * 2,x,y); if (y > mid) update(mid + 1,r,o * 2 + 1,x,y); pushup(o); } int query(int l,int r,int o,int x,int y) { if (x <= l && r <= y) return minn[o]; pushdown(o); int mid = (l + r) >> 1,res = inf; if (x <= mid) res = min(query(l,mid,o * 2,x,y),res); if (y > mid) res = min(query(mid + 1,r,o * 2 + 1,x,y),res); return res; } int main() { scanf("%d%d",&n,&m); build(1,n,1); for (int i = 1; i <= m; i++) scanf("%d%d",&e[i].a,&e[i].b); sort(e + 1,e + 1 + m,cmp); for (int i = 1; i <= m; i++) { if (query(1,n,1,e[i].a,e[i].b) <= 0) continue; update(1,n,1,e[i].a,e[i].b); ans++; } printf("%d\n",ans); return 0; }