bzoj3173: [Tjoi2013]最長上升子序列

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

Source

經過思考發現,由於是從小到大插入的,所以後插入的數對於先前插入的數沒有影響,所以可以直接把最後的序列先求出來,再算一遍LIS就完了
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=100007;
int root;
int val[maxn];
int size1=0;
int rnd[maxn];
int size[maxn];
int ans[maxn];
int cnt=0;
int aa=0;
int tr[maxn][2];
void update(int k)
{
    size[k]=size[tr[k][0]]+size[tr[k][1]]+1;
}
void lturn(int &k){
    int t=tr[k][1];
    tr[k][1]=tr[t][0];
    tr[t][0]=k;
    update(k);
    update(t);
    k=t;
}
void rturn(int &k){
    int t=tr[k][0];
    tr[k][0]=tr[t][1];
    tr[t][1]=k;
    update(k);
    update(t);
    k=t;
}
void insert(int &k,int rank){
    if(k==0){
        k=++size1;
        size[k]=1;
        rnd[k]=rand();
        val[k]=++aa;
        return;
    }
    size[k]++;
    if(size[tr[k][0]]<rank)
    {
        insert(tr[k][1],rank-size[tr[k][0]]-1);
        if(rnd[tr[k][1]]<rnd[k]){
            lturn(k);
        }
    }
    else{
        insert(tr[k][0],rank);
        if(rnd[tr[k][0]]<rnd[k]){
            rturn(k);
        }
    }
}
void dfs(int x){
    if(!x) return;
    dfs(tr[x][0]);
    ans[++cnt]=val[x];
    dfs(tr[x][1]);
}
int g[maxn];
int d[maxn];
int main(){
    memset(g,127/3,sizeof(g));
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u;
        scanf("%d",&u);
        insert(root,u);
    }
    dfs(root);
    int ans1=0;
    for(int i=1;i<=n;i++)
    {
        int u=lower_bound(g+1,g+n+1,ans[i])-g;
        d[ans[i]]=u;
        g[u]=ans[i];
        ans1=max(ans1,u);
    }
    for(int i=1;i<=n;i++)
    {
        d[i]=max(d[i],d[i-1]);
        printf("%d\n",d[i]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章