题目是说A有n张卡片,B有n张卡片,当且仅当A的某张卡片长和宽均不小于B某张卡片的长和宽时可以将其覆盖,覆盖与被覆盖都只能是一次,问最多能有多少次覆盖(长宽不能互换)
将这些卡片以长为第一关键字升序排列,再以宽作为第二关键字升序排列,都相同则将B的放在前面,A的放在后面,然后从头到尾扫描,对于A的卡片,选择可变动性最低的B卡片将其覆盖,即宽小于等于当前卡片里面宽最大的,并删除这张卡片,将答案加1,最后扫完答案也就出来了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct point
{
int x,y;
bool p;
}f[201000];
int tree[201000],i,j,k,a,b,t,n,m;
bool cmp1(point a,point b)
{
return a.y<b.y;
}
bool cmp2(point a,point b)
{
if(a.x==b.x)
{
if(a.y==b.y)return a.p<b.p;
return a.y<b.y;
}
return a.x<b.x;
}
void add(int x)
{
while(x<=m)
{
tree[x]++;
x+=x&(-x);
}
}
void dec(int x)
{
while(x<=m)
{
tree[x]--;
x+=x&(-x);
}
}
int back(int x)
{
int ans=0;
while(x>0)
{
ans+=tree[x];
x-=x&(-x);
}
return ans;
}
int find(int k)
{
int now=0;
for(int i=25;i>=0;i--)
{
now|=(1<<i);
if(now>m || tree[now]>=k)now^=(1<<i);
else k-=tree[now];
}
return now+1;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(tree,0,sizeof(tree));
k=0;
for(i=0;i<n;i++)
{
scanf("%d%d",&f[k].x,&f[k].y);
f[k].p=1;
k++;
}
for(i=0;i<n;i++)
{
scanf("%d%d",&f[k].x,&f[k].y);
f[k].p=0;
k++;
}
sort(f,f+k,cmp1);
a=1;
b=f[0].y;
for(i=0;i<k;i++)
if(b==f[i].y)f[i].y=a;
else
{
a++;
b=f[i].y;
f[i].y=a;
}
m=a;
sort(f,f+k,cmp2);
b=0;
for(i=0;i<k;i++)
{
//printf("%d,%d:%d\n",f[i].x,f[i].y,f[i].p);
if(f[i].p)
{
a=back(f[i].y);
if(a)
{
//printf("%d:%d\n",a,find(a));
dec(find(a));
b++;
}
}
else add(f[i].y);
}
printf("%d\n",b);
}
return 0;
}