题意: 给定n(1<= n <= 100000)个矩形,问最长的递增矩形序列。矩形A和B
A = ((xA1 , yA1 ), (xA2 ,yA2 )) 和 B = ((xB1 , yB1 ), (xB2 , yB2 )),
如果xA2 < xB1 and yA2 < yB1 则 A <= B,问最长L1 <= L2
<= Ln的长度。
LIS序列必须保证单调性,由于我们到左下角的时候已经是定下了lis的位置,所以到右上角的时候必须用左下角确定的位置来更新,需要判断y谁更小。
#include <stdio.h>
#include<stdlib.h>
#define inf 999999999
typedef struct ppp{
int x,y;
int right;
int id;
}point;
inline int max(int kk,int kkk)
{
return kk>kkk?kk:kkk;
}
inline int min(int kk,int kkk)
{
return kk<kkk?kk:kkk;
}
point a[200010]; //拆点
int pos[100002]; //每个矩形的最大链位置,这个位置是由左下角的点决定的
int cmp(const void *p,const void *q)
{
point *pp,*qq;
pp=(point *)p;
qq=(point *)q;
if(pp->x != qq-> x) return pp->x - qq->x; //从左到右,保证后面的矩形只要满足y
return pp->right - qq->right; //保证同x的点先查询,查询只由小于x的点决定,更新的话会影响查询结果
}
int queue[100002]; //Lis
int top=-1;
int n;
int bf(int p,int q,int val)
{
int mid=(p+q)/2;
if(p>=q) return p;
if(queue[mid]>=val) return bf(p,mid,val);
return bf(mid+1,q,val);
}
int main()
{
int ans;
int i;
while(scanf("%d",&n)!=EOF)
{
ans=1;top=-1;
queue[0]=inf; //为了保证一开始左边的点都是链头
if(!n) break;
for(i=0;i<n;i++)
{
scanf("%d%d%d%d",&a[2*i].x,&a[2*i].y,&a[2*i+1].x,&a[2*i+1].y);
a[2*i].right=0;
a[2*i+1].right=1;
a[2*i].id=a[2*i+1].id=i;
}
n*=2;
qsort(a,n,sizeof(a[0]),cmp);
for(i=0;i<n;i++)
{
if(a[i].right)
{
if(top<pos[a[i].id]) queue[++top]=a[i].y; //扩大LIS
else queue[pos[a[i].id]]=min(queue[pos[a[i].id]],a[i].y); //更新
}
else
{
if(queue[0]>=a[i].y) {pos[a[i].id]=0;continue;} //比链头的数还小也是链头
if(queue[top]<a[i].y) {pos[a[i].id]=top+1;continue;} //比链尾的数大为待插
pos[a[i].id]=bf(0,top,a[i].y); //中间值就二分求大于等于的第一个,从而更新
}
}
printf("%d\n",top+1);
}
return 0;
}