[Tjoi2013]最长上升子序列

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2294  Solved: 1153
[Submit][Status][Discuss]

Description

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

Input

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

Sample Input

3
0 0 2

Sample Output

1
1
2

HINT

 

100%的数据 n<=100000

 
 
   首先先不管答案,先看看怎么维护序列。
然后发现这就是一个裸的splay/treap,找到第k大然后旋到根然后把当前点查到后继的左儿子就ojbk了。
 
所以怎么回答询问呢???
 
我们设ans[i]为在最终序列里的以i结尾的最长上升子序列长度,那么第i次询问的答案就是max(ans[1],ans[2],,,,ans[i])。
为什么呢?
因为后加入的肯定都比前i个数大,所以不会对答案产生影响,所以最终序列以前i个数结尾的LIS就是第i次询问的答案。
 
#include<bits/stdc++.h>
#define ll long long
#define maxn 100005
using namespace std;
int root,ch[maxn][2];
int f[maxn],siz[maxn],pos;
int n,m,ans[maxn],g[maxn];
int b[maxn],cnt,tot;

inline int get(int x){
    return ch[f[x]][1]==x;
}

inline void update(int x){
    siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
}

inline void rotate(int x){
    int fa=f[x],ffa=f[fa],tp=get(x);
    ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa;
    ch[x][tp^1]=fa,f[fa]=x;
    f[x]=ffa;
    if(fa==root) root=x;
    if(ffa) ch[ffa][ch[ffa][1]==fa]=x;
    update(fa),update(x);
}

inline void splay(int x){
    for(int fa;(fa=f[x]);rotate(x))
        if(f[fa]) rotate(get(fa)==get(x)?fa:x);
}

inline void kth(int k){
    int now=root;
    while(1){
        if(k<=siz[ch[now][0]]) now=ch[now][0];
        else{
            k-=siz[ch[now][0]]+1;
            if(k<=0){
                splay(now);
                return;
            }
            now=ch[now][1];
        }
    }
}

inline void insert_front(){
    if(!root){
        root=++cnt;
        siz[cnt]=1;
        return;
    }
    
    int now=root,fa;
    while(now){
        siz[now]++;
        fa=now,now=ch[now][0];
    }
    
    siz[++cnt]=1,f[cnt]=fa,ch[fa][0]=cnt;
    update(fa);
}

inline void insert_back(){
    if(!ch[root][1]){
        ch[root][1]=++cnt;
        siz[cnt]=1,f[cnt]=root;
        update(root);
        return;
    }
    
    siz[root]++;
    int now=ch[root][1];
    while(ch[now][0]) siz[now]++,now=ch[now][0];
    siz[now]++;
    
    ch[now][0]=++cnt,siz[cnt]=1,f[cnt]=now;
}

inline void updata(int x,int y){
    for(;x<=n;x+=x&-x) g[x]=max(g[x],y);
}

inline int query(int x){
    int mx=0;
    for(;x;x-=x&-x) mx=max(mx,g[x]);
    return mx;
}

inline void build(int x){
    if(ch[x][0]) build(ch[x][0]);
    b[++tot]=x;
    if(ch[x][1]) build(ch[x][1]);
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&pos);
        if(!pos) insert_front();
        else{
            kth(pos);
            insert_back();
        }
    }
    
    build(root);
    for(int i=1;i<=n;i++){
        int now=query(b[i]-1)+1;
        ans[b[i]]=now;
        updata(b[i],now);
    }
    
    for(int i=1;i<=n;i++){
        ans[i]=max(ans[i],ans[i-1]);
        printf("%d\n",ans[i]);
    }
    
    return 0;
}

 

posted @ 2018-01-31 14:19  蒟蒻JHY  阅读(257)  评论(0编辑  收藏  举报