【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;
}        
View Code

 

posted @ 2017-09-22 22:10  ONION_CYC  阅读(289)  评论(0编辑  收藏  举报