BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]

3173: [Tjoi2013]最长上升子序列

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1613  Solved: 839
[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


插入的数字是递增的,也就是说插入数字后不会改变其他元素的dp值

有一个离线做法:用treap动态把序列弄出来然后求lis

http://hzwer.com/6254.html

 

在线用splay,f表示以当前元素结尾的LIS长度,mx表示他的子树里最大的f

把新插入的元素转到根后,f就是左子树mx+1(不可能有非法的因为递增啊)

 

注意:

1.别忘哨兵

2.别忘更新size时还要+1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
const int N=1e5+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
 
int n,k;
struct node{
    int ch[2],fa,size,v,f,mx;
    node():fa(0){ch[0]=ch[1]=0;}
}t[N];
int sz,root;
inline int wh(int x){return t[pa].ch[1]==x;}
inline void update(int x){
    t[x].size=t[lc].size+t[rc].size+1;
    t[x].mx=max(t[x].f,max(t[lc].mx,t[rc].mx));
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(g) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
inline void splay(int x,int tar){
    for(;t[x].fa!=tar;rotate(x))
        if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x);
    if(tar==0) root=x;
}
inline int kth(int k){
    int x=root,lsize=0;
    while(x){
        int _=lsize+t[lc].size;
        if(_<k&&k<=_+1) return x;
        else if(k<=_) x=lc;
        else lsize=_+1,x=rc;
    }
    return 0;
}
inline int nw(int v){
    sz++;t[sz].v=v;t[sz].size=1;
    return sz;
}
inline void Sol(int k,int v){//printf("Sol %d %d\n",k,v);
    int f=kth(k+1);splay(f,0);//puts("hi");
    int x=kth(k+2);splay(x,f);//printf("ran %d %d\n",f,x);
    lc=nw(v);t[lc].fa=x;
    update(x);update(f);
    splay(sz,0);
    t[sz].f=t[t[sz].ch[0]].mx+1;update(sz); //printf("f %d %d %d\n",sz,t[sz].ch[0],t[sz].f);
    printf("%d\n",t[sz].mx);
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();
    root=nw(0);t[root].ch[1]=nw(N);t[sz].fa=root;
    for(int i=1;i<=n;i++){
        k=read();
        Sol(k,i);
    }
}

 

posted @ 2017-01-14 21:45  Candy?  阅读(344)  评论(0编辑  收藏  举报