省常高NOIP模拟 指引guide

p1
p2


【分析】

做这题可以参考昨天T2的“荒诞”。直观上来说我们每个旅者可以备选的出口是从他自己的坐标,到右上边界的一个矩形。
下图是神奇的两个旅者可以选择的矩形范围:
这里写图片描述
同时考虑x、y坐标,会显得很难下手。我们考虑将旅者和出口的坐标按x坐标排序,再暴力沿x坐标从高到低枚举。这时我们就只要考虑出口y坐标是否比旅者大就可以了。我们可以使用一种神奇的贪心策略,本着“过了这旅者就会少一人”的糟糕精神,我们每枚举一个旅者就尽量将他与另一个出口配对反正后面会有x更小的出口,我才不管,同时为了预留兼容性更强的出口,我们每次只找比旅者y坐标大的第一个出口(也就是后继)。如果没有后继,就默认这旅者出不去了。。。
以上的贪心策略应当是对的无法可想了,但我又一下子证不出来了,请各位大佬明鉴。。。

这里枚举的时候,我们把所有的出口都放在了一个set容器中,可以方便的完成O(logn)的插入、删除和查找后继。当然以上操作也可以用手打treap代替,反正treap随便乱写,常数还小

不需要考虑离散化。(请看题目范围)
代码如下:

#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+1000;
set<int> s;
set<int>::iterator it;
struct node{
    int x,y;
}a[maxn],b[maxn];
int Num,n,ans=0;
void read(int& x){
    x=0;int fl=1;char tmp=getchar();
    while((tmp<'0'||tmp>'9')&&tmp!='-') tmp=getchar();
    if(tmp=='-') fl=-fl,tmp=getchar();
    while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
    x*=fl;
    return ;
}
bool cmp(node x,node y){
    return  x.x>y.x;
}
void slove(){
    int i=1,j=1;
    s.insert(n<<2) ;
    for(int k=(n<<1)-1;k>=0;k--){
        if(i<=n&&a[i].x==k){
            it=s.lower_bound(a[i].y);
            if(*it!=n<<2) s.erase(it),ans++;
            i++;
        }
        else if(b[j].x==k){
            s.insert(b[j].y);
            j++;
        }
    }
}
int main(){
    freopen("guide.in","r",stdin);
    freopen("guide.out","w",stdout);
    cin>>Num>>n;
    for(int i=1;i<=n;i++)
        read(a[i].x),read(a[i].y);
    for(int i=1;i<=n;i++)
        read(b[i].x),read(b[i].y);
    sort(a+1,a+n+1,cmp);
    sort(b+1,b+n+1,cmp);
    slove();
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/81635301