考虑二分求LIS的过程,就是维护一个序列,其中第i个数表示长度为i的最小结尾,而插入操作就是查找第一个大于x的位置并替换掉
用线段树维护,二分的过程也可以用线段树来完成,对线段树可持久化即可
1 #include2 using namespace std; 3 #define N 500005 4 #define mid (l+r>>1) 5 int B,V,n,p,x,y,r[N],ans[N],f[N*30],ls[N*30],rs[N*30]; 6 int copy(int k){ 7 f[++V]=f[k]; 8 ls[V]=ls[k]; 9 rs[V]=rs[k]; 10 return V; 11 } 12 void build(int &k,int l,int r){ 13 f[k=++V]=0x3f3f3f3f; 14 if (l==r){ 15 if (!l)f[k]=-0x3f3f3f3f; 16 return; 17 } 18 build(ls[k],l,mid); 19 build(rs[k],mid+1,r); 20 f[k]=max(f[ls[k]],f[rs[k]]); 21 } 22 void update(int &k,int l,int r,int x,int y){ 23 k=copy(k); 24 if (l==r){ 25 f[k]=y; 26 return; 27 } 28 if (x<=mid)update(ls[k],l,mid,x,y); 29 else update(rs[k],mid+1,r,x,y); 30 f[k]=max(f[ls[k]],f[rs[k]]); 31 } 32 int query(int k,int l,int r,int x){ 33 if (l==r)return l; 34 if (f[ls[k]]>x)return query(ls[k],l,mid,x); 35 return query(rs[k],mid+1,r,x); 36 } 37 int main(){ 38 scanf("%d",&n); 39 build(r[0],0,n); 40 for(int i=1;i<=n;i++){ 41 scanf("%d%d",&p,&x); 42 if (p)printf("%d\n",ans[B=x]); 43 else{ 44 B++; 45 y=query(r[B]=r[B-1],0,n,x); 46 if (y)update(r[B],0,n,y,x); 47 printf("%d\n",ans[B]=max(ans[B-1],y)); 48 } 49 } 50 }