先用线段树找到每个数的位置,然后用二分求LIS。
ACcode:
#include<stdio.h>
#include<iostream>
using namespace std;
const int size=111111;
int pos[size];
int sum[size<<2],num[size];
void build(int rt,int l,int r)
{
sum[rt]=r-l+1;
if (l==r) return ;
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
void update(int rt,int l,int r,int p,int k)
{
if (l==r)
{
pos[k]=r;
sum[rt]=0;
return ;
}
int m=(l+r)>>1;
if (sum[rt<<1]>=p) update(rt<<1,l,m,p,k);
else update(rt<<1|1,m+1,r,p-sum[rt<<1],k);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int main()
{
int n,i,k,m,T,cas=0;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
build(1,0,n-1);
printf("Case #%d:\n",++cas);
for (i=1; i<=n; i++) scanf("%d",&num[i]);
for (i=n; i>0; i--)
update(1,0,n-1,num[i]+1,i);
for (m=0,i=1; i<=n; i++)
{
k=pos[i];
if (m==0||k>num[m]) num[++m]=k;
else
{
int l=1,r=m;
while (l<=r)
{
int c=(l+r)>>1;
if (num[c]<k) l=c+1;
else if (num[c]>k) r=c-1;
else
{
l=c;
break;
}
}
num[l]=k;
}
printf("%d\n",m);
}
puts("");
}
return 0;
}