【BZOJ】1707: [Usaco2007 Nov]tanning分配防晒霜
【算法】贪心扫描线(+堆)
【题意】给定n头牛有区间[a,b],m个防晒霜值为ai,每个可以使用bi次,每次可以使包含它的区间涂到防晒霜,问最多被涂牛数。
【题解】
参考:[bzoj1707]: [Usaco2007 Nov]tanning分配防晒霜 by czllgzmzl
本题同样是区间和点的贪心,可以参考另一道题【BZOJ】1828: [Usaco2010 Mar]balloc 农场分配(经典贪心)
区间和点的贪心有两种经典做法,本题一样。
一、从区间角度出发,按区间右端点排序
区间第二关键字按左端点从小到大排序,防晒霜排序后,对于每个区间选择其最左的防晒霜。
这个过程可以用二分+并查集实现,参考上帝造题2。
二、从点的角度出发,按区间左端点排序
对于每个防晒霜,对左影响一致(左边的能用都用了)的情况下,给右端点最小的。
用堆实现。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cctype> using namespace std; const int maxn=2510; priority_queue<int,vector<int>,greater<int> >q; int n,m; struct interval{int x,y;}b[maxn]; struct point{int x,c;}a[maxn]; bool cmp(interval a,interval b){return a.x<b.x;} bool cmp2(point a,point b){return a.x<b.x;} int read() { char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t; } int main(){ m=read();n=read(); for(int i=1;i<=m;i++)b[i].x=read(),b[i].y=read(); for(int i=1;i<=n;i++)a[i].x=read(),a[i].c=read(); sort(b+1,b+m+1,cmp); sort(a+1,a+n+1,cmp2); int now=0,ans=0; for(int i=1;i<=n;i++){ while(now<m&&b[now+1].x<=a[i].x)now++,q.push(b[now].y); for(int j=1;j<=a[i].c;j++){ while(!q.empty()&&q.top()<a[i].x)q.pop(); if(q.empty())break; ans++;q.pop(); } } printf("%d",ans); return 0; }