【题目链接】

BZOJ 3173 最长上升子序列 [TJOI2013]

【题目描述】

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

【解题思路】

题目十分简单明了,而我们的思路也是如此。

考虑一个数$x$加入时的影响,所有以$i(i < x)$结尾的上升子序列长度$f_i$都不会受到影响,因此我们只需要计算以$x$结尾的最长上升子序列长度$f_x$,设插入到$k$位置,则$f_x = max\{f_i\} + 1 (i < k)$,也就是说,我们需要实现支持插入的前缀最大值查询。

平衡树。

【AC代码】

选择了Treap,然而速度一般。

#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <utility>
 
#define TreapCouple std::pair<Node*, Node*>
 
template <typename Item> struct Treap{
    struct Node{
        Item value, max;
        int fix, size;
        Node *lchild, *rchild;
 
        Node(const Item &x){
            value = max = x;
            size = 1;
            fix = rand();
            lchild = rchild = NULL;
        }

        ~Node(){
            if(lchild) delete lchild;
            if(rchild) delete rchild;
        }

        int lsize(){
            return lchild ? lchild->size : 0;
        }
 
        int rsize(){
            return rchild ? rchild->size : 0;
        }
 
        void update(){
            size = lsize() + rsize() + 1;
            max = value;
            if(lchild) max = std::max(max, lchild->max);
            if(rchild) max = std::max(max, rchild->max);
        }
 
        TreapCouple split(int k){
            if(!this) return TreapCouple(NULL, NULL);
 
            TreapCouple couple;
            if(lsize() >= k){
                couple = lchild->split(k);
                lchild = couple.second;
                couple.second = this;
            }
            else{
                couple = rchild->split(k - lsize() - 1);
                rchild = couple.first;
                couple.first = this;
            }
 
            update();
 
            return couple;
        }
    };
 
    Node *root;
    Treap(){
        root = NULL;
        srand(19991205);
    }

    ~Treap(){
        if(root) delete root;
    }
 
    Node* merge(Node *a, Node *b){
        if(!a) return b;
        if(!b) return a;
 
        if(a->fix > b->fix){
            a->rchild = merge(a->rchild, b);
 
            a->update();
            return a;
        }
        else{
            b->lchild = merge(a, b->lchild);
 
            b->update();
            return b;
        }
    };
 
    void insert(const Item &x, int k){
        TreapCouple couple = root->split(k);
        Node *v = new Node(x);
        root = merge(couple.first, merge(v, couple.second));
    }
 
    Item query(int k){
        if(k == 0) return 0; // 为方便,边界写在这儿了
        TreapCouple couple = root->split(k);
 
        Item ans = couple.first->max;
 
        root = merge(couple.first, couple.second);
 
        return ans;
    }
};

int main(){
    Treap<int> *T = new Treap<int>;

    int n;
    scanf("%d", &n);

    for(int i = 1; i <= n; i++){
        int x, k;
        scanf("%d", &k);

        x = T->query(k) + 1;

        T->insert(x, k);

        printf("%d\n", T->query(i));
    }
    
    return 0;
}

就是这样啦