zoukankan      html  css  js  c++  java
  • bzoj3173 最长上升子序列 题解--Treap+nlogn求LIS

    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

    题解


     

    树的部分比较好理解,读到了位置insert即可,注意插入的时候关键字是cnt,也就是当前数的值。

    然后LIS的部分今天才学会,就是nlogn的办法,如果不用stl的话就是二分查找,网上详解很多,在此不多说。

    代码


    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int v,n,dp[210000],b[210000],d[210000],cnt,tot,ans[210000],mx,root,p;
    struct treap{
        int ls,rs,pri,siz,val;
    }a[200010];
    void pushup(int o){
        a[o].siz=a[a[o].ls].siz+a[a[o].rs].siz+1;
        return;
    }
    void lturn(int &o){
        int t=a[o].rs;
        a[o].rs=a[t].ls;
        a[t].ls=o;
        a[t].siz=a[o].siz;
        pushup(o);
        o=t;
    }
    void rturn(int &o){
        int t=a[o].ls;
        a[o].ls=a[t].rs;
        a[t].rs=o;
        a[t].siz=a[o].siz;
        pushup(o);
        o=t;
    }
    void insert(int p,int &o){
        if(!o){
            o=++cnt;
            a[o]=(treap){0,0,rand(),1,1};
            return;
        }
        a[o].siz++;
        //
        if(p<=a[a[o].ls].siz){
            insert(p,a[o].ls);
            if(a[o].pri<a[a[o].ls].pri)rturn(o);
        }
        else {
            insert(p-a[a[o].ls].siz-1,a[o].rs);
            if(a[o].pri<a[a[o].rs].pri)lturn(o);
        }
    }
    void dfs(int o){
        if(a[o].ls!=0)dfs(a[o].ls);
        b[++tot]=o;
        if(a[o].rs!=0)dfs(a[o].rs);
    }
    void getlis(){
        memset(d,0x3f,sizeof(d));
        d[0]=-1000000;
        for(int i=1;i<=tot;i++){
            int t=upper_bound(d,d+mx+1,b[i])-d;
            if(d[t-1]<=b[i])d[t]=min(d[t],b[i]);
            ans[b[i]]=t;
            mx=max(mx,t);
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&p);
            insert(p,root);
        }
        dfs(root);
        getlis();
        for(int i=1;i<=n;++i){
            ans[i]=max(ans[i-1],ans[i]);
            printf("%d
    ",ans[i]);
        }
        return 0;
    }

     

  • 相关阅读:
    概率论与统计学---笔记
    实用概率论与数理统计学--笔记
    并发编程总结5-JUC-REENTRANTLOCK-3(非公平锁)
    并发编程总结4-JUC-REENTRANTLOCK-2(公平锁)
    并发编程总结3——JUC-LOCK-1
    DOCKER & SWARM1.2
    Docker
    hdfs命令
    并发编程总结2——java线程基础2
    并发编程总结1——java线程基础1
  • 原文地址:https://www.cnblogs.com/Requiescat/p/7551731.html
Copyright © 2011-2022 走看看