Luogu P4309 [TJOI2013]最长上升子序列

优秀的性质:从 \(1\)\(n\) 依次插入,所以我们每次只用在比当前位置靠前的所有 \(f[i]\) 中取个 \(\max\) 然后 \(+1\) ;我们可以用 平衡树 模拟这个过程。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=100010;
int n,tot,rt;
int ch[N][2],sz[N],vl[N],pos[N],f[N],dat[N];
#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
inline int cre(int v,int p) {
  R tr=++tot;
  dat[tr]=rand(),sz[tr]=1,vl[tr]=f[pos[tr]=p]=v;
  return tr;
}
inline void upd(int tr) {
  sz[tr]=sz[ls(tr)]+sz[rs(tr)]+1;
  vl[tr]=max(f[pos[tr]],max(vl[ls(tr)],vl[rs(tr)]));
}
inline void split(int tr,int& x,int& y,int k) {
  if(!tr) return x=y=0,void();
  if(sz[ls(tr)]<k) x=tr,split(rs(tr),rs(x),y,k-sz[ls(tr)]-1);
  else y=tr,split(ls(tr),x,ls(y),k);
  upd(tr);
}
inline int merge(int x,int y) {
  if(!x||!y) return x+y;
  if(dat[x]<dat[y]) {
    rs(x)=merge(rs(x),y),upd(x);
    return x;
  } ls(y)=merge(x,ls(y)),upd(y);
  return y;
}
inline void main() {
  n=g(); srand(20040109);
  for(R i=1,v,x,y,z;i<=n;++i) {
    v=g();
    split(rt,x,y,v),
    z=cre(vl[x]+1,i);
    x=merge(x,z);
    rt=merge(x,y);
    printf("%d\n",vl[rt]);
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.19

posted @ 2020-01-19 10:10  LuitaryiJack  阅读(172)  评论(0编辑  收藏  举报