【分析】
做这题可以参考昨天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;
}