• [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
    ",ans[i]);
        }
        
        return 0;
    }
  • 相关阅读:
    Python封装发送信息到钉钉群
    centos 7.6 安装php70
    小米5s plus刷机
    centos 7 安装webmin
    交易开拓者旗舰版(TB旗舰版)软件升级中如何迁移用户数据
    centos 7.6 修改vim配色方案
    centos 7.0 读写ntfs分区
    centos iptables 数据转发
    centos 7.6 配置VNC
    win下maridb 10.1.8下主从复制配置
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8392005.html
Copyright © 2020-2023  润新知