JSOI2007 建筑抢修

题目链接:戳我

开始以为是按照修建时间短的排序,先把修建时间短的修了。
但是这样显然有问题,因为可能前面的倒塌时间靠后,你先修了,后面塌的就不能修了。

所以要按倒塌时间排序开始修。
然后如果当前的建筑物来得及修,当然是要修的。
这时候我们维护一个已经修过的建筑物的大根堆(优先队列)。
如果不能修,看看是否从原先修建过的建筑物中取出那个时间最长的之后,就可以修这个了。如果可以的话,就把堆顶pop掉,然后把这个放进堆中,表示不修那个修这个。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define MAXN 300010
using namespace std;
int n,ans,now;
priority_queue<int,vector<int>,less<int> >q;
struct Node{int a,b;}node[MAXN<<1];
inline bool cmp(struct Node x,struct Node y){return x.b<y.b;}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&node[i].a,&node[i].b);
    sort(&node[1],&node[n+1],cmp);
    // for(int i=1;i<=n;i++)printf("%d %d\n",node[i].a,node[i].b);
    for(int i=1;i<=n;i++)
    {
        // printf("i=%d now=%d %d %d\n",i,now,node[i].a,node[i].b);
        if(now+node[i].a>node[i].b&&(!q.empty()))
        {
            int u=q.top();
            if(now-u+node[i].a<=node[i].b&&u>node[i].a) 
            {
                now=now-u+node[i].a;
                q.pop();
                q.push(node[i].a);
            }
        }
        else ans++,now+=node[i].a,q.push(node[i].a);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-05-22 23:42  风浔凌  阅读(153)  评论(0编辑  收藏  举报