【NOIP模拟】指引

题面

N 名迷途的旅者需要小 X 的指引。

初始时,每一名旅者 i 位于坐标(Ai,Bi)处,旅者们只能够向右或是向上移动.

也就是说,他们只能够增加自己的某一维坐标,而不能减小它们。

这片大地上同样存在者 N 个出口,每一个出口 i 位于坐标(Ci,Di)处,一个出一旦被某个旅者通过,它们就会一并消失。

请帮助小 X 计算他至多能够指引多少旅者离开这片大地。

n<=105

分析

按x升序排序贪心一波,对于每个出口,把它右边的人全部加进来,然后选择y比它小但y最大的那个。

就是这个操作,我思考到底用什么数据结构维护。

恕我孤陋寡闻,不知道set是可以lower_bound。我就只能用优先队列硬怼,每次把怼出来的但是比现在这个高度大的先放一个vector里存一下。

while(!q.empty())
    {
         pii tmp=q.top();q.pop();
         if(tmp.first<=ex[i].y){ans++;break;}    
        v.push_back(tmp);
    }
    if(!v.empty())
        for(int j=0;j<v.size();j++)q.push(v[j]);
    while(!v.empty())v.pop_back(); 

 

我是真的想了lower_bound的,对天发誓!但是如果直接vector里二分,还需要排序,和上面这种硬怼的做法都是n2logn的

孤陋寡闻的锅。

代码

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,l=1,num,ans,cnt,now=1;
struct email
{
    int x,y,id;
}a[N],b[N],c[N],d[N],ex[N];
set<int>s;
template<class T>
inline void read(T &x)
{
    x=0;int f=1;static char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
bool cmp1(email a,email b){return a.x<b.x;}
int main()
{
    for(int i=1;i<=n;i++)read(a[i].x),read(a[i].y),a[i].id=i;
    for(int i=1;i<=n;i++)read(b[i].x),read(b[i].y);
    for(int i=1;i<=n;i++)c[i]=a[i],d[i]=b[i];
    sort(c+1,c+1+n,cmp1);sort(d+1,d+1+n,cmp1);
    while(d[l].x<c[1].x)l++;
    for(int i=l;i<=n;i++)ex[++cnt]=d[i];
    sort(ex+1,ex+1+cnt,cmp1);sort(a+1,a+1+n,cmp1);
    for(int i=1;i<=cnt;i++)
    {
        while(now<=n&&ex[i].x>=a[now].x)s.insert(a[now].y),now++;
        set <int> :: iterator tmp=s.lower_bound(ex[i].y);
        if(tmp==s.begin())continue;
        tmp--;ans++;s.erase(tmp);
    }
    printf("%d\n",ans);
    return 0;
    
}

 

posted @ 2018-11-05 15:13  WJEMail  阅读(469)  评论(7编辑  收藏  举报