bzoj3173 [Tjoi2013]最长上升子序列
题意:依此插入1-n 求每插完一次的LIS
分析:每个数是按照升序插入的,因此每新加入一个数,不会影响之前的答案,那么我们就可以求出最后的序列,这样我们可以求出以每个数为结尾的LIS,那么答案 ans[i]=max(ans[i],ans[i-1]).
LIS现学的囧……理解是挺好理解的……实现囧……
d[len]:长度为len的LIS的结尾的最小值
d[i]=max(j)+1 其中d[j] < a[i]
d单调 二分O(nlogn)
插入得到最后序列 Treap
记:
iteratorlower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。
iterator upper_bound( const key_type &key ):返回一个迭代器,指向键值>key的第一个元素。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define N 100005
#define mp make_pair
#define pa pair<int,int>
#define inf 1<<30
using namespace std;
struct Node{int ls,rs,v,key,sz;}t[N];
void upd(int k){t[k].sz=t[t[k].ls].sz+t[t[k].rs].sz+1;}
int num,root,n,x,cnt,a[N],d[N],ans[N],da[N];
int merge(int a,int b){
if(a==0||b==0) return a+b;
if(t[a].key<t[b].key){t[a].rs=merge(t[a].rs,b);upd(a);return a;}
else {t[b].ls=merge(a,t[b].ls);upd(b);return b;}
}
pa split(int k,int x){
if(x==0) return mp(0,k);
int ls=t[k].ls,rs=t[k].rs;pa tmp;
if(t[ls].sz==x) {t[k].ls=0;upd(k);return mp(ls,k);}
if(t[ls].sz==x-1) {t[k].rs=0;upd(k);return mp(k,rs);}
if(t[ls].sz>x) {tmp=split(ls,x);t[k].ls=tmp.second;upd(k);return mp(tmp.first,k);}
if(t[ls].sz<x-1) {tmp=split(rs,x-t[ls].sz-1);t[k].rs=tmp.first;upd(k);return mp(k,tmp.second);}
}
void ins(int x,int v){
int k=x-1;
t[++num].ls=0;t[num].rs=0;t[num].sz=1;
t[num].v=v;t[num].key=rand();
pa tmp=split(root,k);
root=merge(tmp.first,num);
root=merge(root,tmp.second);
}
void dfs(int i){
if(!i) return;
dfs(t[i].ls);
a[++cnt]=i;
dfs(t[i].rs);
}
void getans(){
memset(d,127,sizeof(d));
d[0]=-inf;d[1]=a[1];ans[a[1]]=1;
int len=1;
for(int i=2;i<=n;i++){
int pos=upper_bound(d,d+len,a[i])-d;
if(a[i]>d[len]) d[++len]=a[i],ans[a[i]]=len;
else d[pos]=min(d[pos],a[i]),ans[a[i]]=pos;
}
for(int i=1;i<=n;i++) ans[i]=max(ans[i],ans[i-1]);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&x),ins(x+1,i);
dfs(root);
getans();
}