Thanks to visit codestin.com
Credit goes to hitonanode.github.io

cplib-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: Longest increasing subsequence (LIS, 最長増加部分列)
(other_algorithms/longest_increasing_subsequence.hpp)

列の最長増加部分列 (LIS)・最長非減少部分列の長さや,これらの部分列を構成する要素の添字列を得る.

使用方法

vector<long long> A(N);

// LIS の長さ O(N log len(lis))
int lis_len = lis_length(A, LisType::StrictlyIncreasing);
// 最長非減少部分列の長さ O(N log len(lis))
int lnds_len = lis_length(A, LisType::Nondecreasing);

// LIS を構成する要素の添字列を取得 O(N log len(lis))
vector<int> lis_idxs = longest_increasing_subsequence(A, LisType::StrictlyIncreasing).get_lis_indices();

問題例

Verified with

Code

#pragma once
#include <algorithm>
#include <memory>
#include <vector>

enum class LisType {
    StrictlyIncreasing,
    Nondecreasing,
};

// Calculate (only) length of longest increasing subsequence (LIS)
// Complexity: O(n log n)
template <class T>
int lis_length(const std::vector<T> &seq, LisType lis_type = LisType::StrictlyIncreasing) {
    std::vector<T> dp;
    for (const T &x : seq) {
        if (auto itr = (lis_type == LisType::StrictlyIncreasing
                            ? std::lower_bound(begin(dp), end(dp), x)
                            : std::upper_bound(begin(dp), end(dp), x));
            itr == end(dp)) {
            dp.push_back(x);
        } else {
            *itr = x;
        }
    }
    return dp.size();
}

template <class T> struct longest_increasing_subsequence {

    LisType lis_type_ = LisType::StrictlyIncreasing;
    int current_idx = 0;

    struct Node {
        std::shared_ptr<Node> par;
        int len, idx;
        T v;
    };

    std::vector<T> dp;
    std::vector<std::shared_ptr<Node>> ptrs;

    // Complexity: O(1)
    longest_increasing_subsequence(LisType lis_type) : lis_type_(lis_type) {}

    // Complexity: O(N log N)
    longest_increasing_subsequence(const std::vector<T> &seq, LisType lis_type)
        : lis_type_(lis_type) {
        for (const T &x : seq) add(x);
    }

    // Complexity: O(log N)
    std::shared_ptr<Node> add(const T &x) {
        auto itr =
            (lis_type_ == LisType::StrictlyIncreasing ? std::lower_bound(begin(dp), end(dp), x)
                                                      : std::upper_bound(begin(dp), end(dp), x));
        int cur = std::distance(begin(dp), itr);
        std::shared_ptr<Node> prv = (begin(dp) == itr ? nullptr : ptrs.at(cur - 1));

        std::shared_ptr<Node> node(
            new Node{prv, (prv == nullptr ? 0 : prv->len) + 1, current_idx++, x});

        if (itr == end(dp)) {
            dp.push_back(x), ptrs.push_back(node);
        } else {
            dp.at(cur) = x, ptrs.at(cur) = node;
        }
        return node;
    }

    std::shared_ptr<Node> head() const { return ptrs.empty() ? nullptr : ptrs.back(); }

    // LIS をなす添字列を出力
    // Complexity: O(N)
    std::vector<int> get_lis_indices() const {
        std::vector<int> ret;
        for (auto ptr = head(); ptr != nullptr; ptr = ptr->par) ret.push_back(ptr->idx);
        std::reverse(ret.begin(), ret.end());
        return ret;
    }
};
#line 2 "other_algorithms/longest_increasing_subsequence.hpp"
#include <algorithm>
#include <memory>
#include <vector>

enum class LisType {
    StrictlyIncreasing,
    Nondecreasing,
};

// Calculate (only) length of longest increasing subsequence (LIS)
// Complexity: O(n log n)
template <class T>
int lis_length(const std::vector<T> &seq, LisType lis_type = LisType::StrictlyIncreasing) {
    std::vector<T> dp;
    for (const T &x : seq) {
        if (auto itr = (lis_type == LisType::StrictlyIncreasing
                            ? std::lower_bound(begin(dp), end(dp), x)
                            : std::upper_bound(begin(dp), end(dp), x));
            itr == end(dp)) {
            dp.push_back(x);
        } else {
            *itr = x;
        }
    }
    return dp.size();
}

template <class T> struct longest_increasing_subsequence {

    LisType lis_type_ = LisType::StrictlyIncreasing;
    int current_idx = 0;

    struct Node {
        std::shared_ptr<Node> par;
        int len, idx;
        T v;
    };

    std::vector<T> dp;
    std::vector<std::shared_ptr<Node>> ptrs;

    // Complexity: O(1)
    longest_increasing_subsequence(LisType lis_type) : lis_type_(lis_type) {}

    // Complexity: O(N log N)
    longest_increasing_subsequence(const std::vector<T> &seq, LisType lis_type)
        : lis_type_(lis_type) {
        for (const T &x : seq) add(x);
    }

    // Complexity: O(log N)
    std::shared_ptr<Node> add(const T &x) {
        auto itr =
            (lis_type_ == LisType::StrictlyIncreasing ? std::lower_bound(begin(dp), end(dp), x)
                                                      : std::upper_bound(begin(dp), end(dp), x));
        int cur = std::distance(begin(dp), itr);
        std::shared_ptr<Node> prv = (begin(dp) == itr ? nullptr : ptrs.at(cur - 1));

        std::shared_ptr<Node> node(
            new Node{prv, (prv == nullptr ? 0 : prv->len) + 1, current_idx++, x});

        if (itr == end(dp)) {
            dp.push_back(x), ptrs.push_back(node);
        } else {
            dp.at(cur) = x, ptrs.at(cur) = node;
        }
        return node;
    }

    std::shared_ptr<Node> head() const { return ptrs.empty() ? nullptr : ptrs.back(); }

    // LIS をなす添字列を出力
    // Complexity: O(N)
    std::vector<int> get_lis_indices() const {
        std::vector<int> ret;
        for (auto ptr = head(); ptr != nullptr; ptr = ptr->par) ret.push_back(ptr->idx);
        std::reverse(ret.begin(), ret.end());
        return ret;
    }
};
Back to top page