题目大意:Alice和Bob各有N张卡,每张卡有宽和高两个属性,如果一张卡的宽和高都不小于另一张卡,就能将其覆盖,求Alice最多能覆盖Bob多少张卡。
题目的规模非常大,因此普通的O(n^2)算法是行不通的,所以考虑用容器做,这里用multiset
(#include<set>)自动升序排列。
思路 先按任一属性(我选宽度w)把Alice和Bob的卡分别按升序排列,然后从头遍历Alice的卡(a[i]),每次把宽度小于等于a[i]宽度的Bob的卡(b[i])放到multiset的容器中,然后从中取出高度最接近a[i]的卡被覆盖。如此反复就能得到最大值。
这里用到了一个multiset的函数 lower_bound(x) 返回第一个大于x的元素(不是小于)
或 upper_bound(x) 返回第一个大于等于x的元素。
代码
using namespace std;
struct card{int h;int w;};
card a[200000],b[200000];
multiset<int> s;
multiset<int>::iterator it;
bool order(card x,card y)
{
return x.w<y.w;
}
int main()
{
int t;
int i;
int n;
scanf("%d",&t);
for(;t>0;t--)
{
s.clear();
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i].h,&a[i].w);}for(i=0;i<n;i++)
{
scanf("%d %d",&b[i].h,&b[i].w);
}
sort(a,a+n,order);
sort(b,b+n,order);
int j=0;
int ans=0;
for(i=0;i<n;i++)
{
while(j<n &&b [j].w<=a[i].w)
{
s.insert(b[j].h); //这里只要放入高即可
j++;
}
it=s.lower_bound(a[i].h);
if(s.size() > 0 && it!=s.begin())it--;// 因为返回是第一个大于它的数,所以前一个必定小于等于它(升序排列)
if(s.size() > 0 && *it<=a[i].h) // 防止t没--也进入判断(如果it就指向开头begin也没法退呀)
{
ans++;
s.erase(it); //踢出,相当于已经被覆盖
}
}
printf("%d\n",ans);
}
return 0;
}