BZOJ 5029: 贴小广告【堆+模拟】

5029: 贴小广告

Time Limit: 10 Sec Memory Limit: 256 MB

Description

现在有一堵墙,墙上分为若干个单元。接下来会来n个人在墙上贴小广告。每次每个人选择墙上连续一段的单元贴
上自己公司与众不同的小广告。因为小广告可能会出现被覆盖的情况,由于公司之间存在竞争,后贴广告的人想让
别人看不见前面公司的广告,所以会将前面的广告完全覆盖。因此对于墙上的某个单元上贴的小广告中只有贴的最
晚的能被看见。现在想要知道n个人依次贴完后,墙上共能看到多少种小广告?

Input

输入文件第一行有一个整数 n。
接下来 n 行每行 2 个整数 li、ri,表示这个人在第li个单元到第ri个单元贴了小广告。
1 <= n,m <= 10^5 , 1<=li<=ri<=10^7

Output

输出所有人贴完后墙上能看到多少种小广告?

Sample Input

5
1 4
2 6
8 10
3 4
7 10

Sample Output

4

题解

我们将Ai,Bi这条线段拆成两个点Ai和Bi+1,在这两个点之间的所有的点都有i这个编号的海报。编号越大放在越前面,没遇到x这个点,都有取出当前的最大编号,并且带插入和删除的,那么就建一个大根堆,维护当前最大编号就可以了。

代码如下

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,hsh[100005],Ans;
bool vis[100005];
priority_queue<int> hep;
struct xcw{
    int x,id;bool f;
    bool operator <(const xcw b)const{return x<b.x;}
}a[200005];
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int L,R;scanf("%d%d",&L,&R);n=max(n,R);
        a[i*2-1]=(xcw){L,i,1},a[i*2]=(xcw){R+1,i,0};
    }
    sort(a+1,a+1+2*m);
    for(int i=1,j=1;i<=n;i++){
        while(a[j].x==i&&j<=2*m){
            vis[a[j].id]=a[j].f;
            if(vis[a[j].id]) hep.push(a[j].id);
            j++;
        }
        while(!hep.empty()&&!vis[hep.top()]) hep.pop();
        if(!hep.empty()) hsh[hep.top()]=1;
    }
    for(int i=1;i<=m;i++) Ans+=hsh[i];
    printf("%d\n",Ans);
    return 0;
}
posted @ 2018-05-03 16:46  XSamsara  阅读(137)  评论(0编辑  收藏  举报