指引 (HG 2018.8.13 T1)
hicc0305
2018-08-13 19:10:32
![](https://cdn.luogu.com.cn/upload/pic/28366.png)
![](https://cdn.luogu.com.cn/upload/pic/28367.png)
不会用STL真的是大亏。。虽然我也没想出来怎么贪心。。
首先们看数据范围,横坐标、纵坐标都两两不相同,然后横纵坐标的大小都<2*n,这说明了什么?这说明我们已经不用离散化了,所有的横坐标、纵坐标都是连在一起的!!
于是,我们可以开一个大小为2*10^5的数组,f[i]记录i这个横坐标是属于人还是属于洞的,h[i]记录这个横坐标所对的纵坐标是多少。
然后,从0~2*10^5我们扫一遍。如果是人的坐标,就把它插进set里,如果是洞的坐标,我们就在插进set里的人的坐标中,找到最后一个纵坐标小于等于这个洞的坐标的人(横坐标已经保证要小了),如果没有这么一个人。。那么说明这个可怜的洞没人走,于是ans不++。有人的话,就把这个纵坐标离洞最近的人走到这个洞,然后ans++,并把这个洞删掉。 找这个人可以用set自带的lower_bound实现。
为什么是对的呢?因为我们从左到右扫,并不用担心set里的人的横坐标比当前扫到的洞的横坐标大,所以,我们尽量满足纵坐标靠近当前洞的人,这样贪心显然是正确的。
代码如下:
```cpp
#include<map>
#include<set>
#include<list>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int read()
{
int x=0,flag=0;
char ch=getchar();
if(ch=='-') flag=1;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
if(flag) return -x;
return x;
}
int write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>=10)write(x/10);
putchar(x%10+'0');
}
int n;
int f[200100],h[200100];
set <int> s;
set <int> :: iterator it;
int main()
{
int tmp=read(),ans=0;
n=read();
for(int i=1;i<=n;i++)
{
int x=read(),y=read();
f[x]=1,h[x]=y;
}
for(int i=1;i<=n;i++)
{
int x=read(),y=read();
f[x]=0,h[x]=y;
}
for(int i=0;i<2*n;i++)
{
if(f[i]) s.insert(h[i]);
else
{
it=s.lower_bound(h[i]);
if(it==s.begin()) continue;//没人可以走到当前洞了
ans++;
s.erase(--it);//注意,lower_bound找到的是第一个大于等于h[i]的人,所以要--,才是最后一个纵坐标小于等于h[i]的人
}
}
write(ans);
return 0;
}
```