题目描述
农夫约翰最近开了一个新的牲口棚屋,并且现在接受来自奶牛的分配畜栏请求因为其中的一些畜栏有更好风景。
畜栏包括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
【解题思路】
贪心+线段树维护
如何贪心:我们可以考虑两种线段间的位置关系,在纸上画出,共有5种需要考虑的情况,这里就不再赘述。
我们要尽量不让现在的线段影响后面线段的选择,而错过最优解,就先将线段按照B排序(由小到大),若B相同,就按照A排(由大到小)。
如何使用线段树维护:线段树用来维护区间剩余容量的最小值,如果这个区间的剩余容量最小值为0,那么就不能选择这个区间。
我们还可以用懒标记来优化一下。
【code】
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int INF=1<<30; 6 int n,m,ans; 7 struct Node{ 8 int l,r; 9 }a[100005]; 10 int c[100005]; 11 struct Tree{ 12 int l,r,minv,lazy; 13 }t[400005]; 14 inline bool cmp(Node a,Node b){ 15 if(a.r!=b.r)return a.r<b.r; 16 return a.l>b.l; 17 } 18 inline int Min(int a,int b){ 19 return a<b?a:b; 20 } 21 inline void BuildTree(int l,int r,int rt){ 22 t[rt].l=l; 23 t[rt].r=r; 24 if(l==r){ 25 t[rt].minv=c[l]; 26 return; 27 } 28 int mid=l+r>>1; 29 BuildTree(l,mid,rt<<1); 30 BuildTree(mid+1,r,rt<<1|1); 31 t[rt].minv=Min(t[rt<<1].minv,t[rt<<1|1].minv); 32 return; 33 } 34 inline void work(int k1,int L,int R,int k){ 35 if(t[k1].l>R||t[k1].r<L)return; 36 if(t[k1].l>=L&&t[k1].r<=R){ 37 t[k1].minv+=k; 38 t[k1].lazy+=k; 39 return; 40 } 41 work(k1<<1,L,R,k); 42 work(k1<<1|1,L,R,k); 43 t[k1].minv=Min(t[k1<<1].minv,t[k1<<1|1].minv); 44 } 45 inline void pushdown(int k){ 46 t[k<<1].lazy+=t[k].lazy; 47 t[k<<1].minv+=t[k].lazy; 48 t[k<<1|1].lazy+=t[k].lazy; 49 t[k<<1|1].minv+=t[k].lazy; 50 t[k].lazy=0; 51 return ; 52 } 53 inline int find(int k1,int L,int R){ 54 if(t[k1].l>R||t[k1].r<L)return INF; 55 if(t[k1].l>=L&&t[k1].r<=R)return t[k1].minv; 56 pushdown(k1); 57 return Min(find(k1<<1,L,R),find(k1<<1|1,L,R)); 58 } 59 int main(){ 60 //freopen("balloc.in","r",stdin); 61 //freopen("balloc.out","w",stdout); 62 scanf("%d%d",&n,&m); 63 for(register int i=1;i<=n;i++) 64 scanf("%d",&c[i]); 65 BuildTree(1,n,1); 66 for(register int i=1;i<=m;i++) 67 scanf("%d%d",&a[i].l,&a[i].r); 68 sort(a+1,a+m+1,cmp); 69 for(register int i=1;i<=m;i++){ 70 if(find(1,a[i].l,a[i].r)){ 71 work(1,a[i].l,a[i].r,-1); 72 ans++; 73 } 74 } 75 printf("%d\n",ans); 76 return 0; 77 }