cp-includes

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

View the Project on GitHub rsalesc/cp-includes

:warning: matroid/v2/MatroidIntersection.cpp

Depends on

Code

#ifndef _LIB_MATROID_INTERSECTION_V2
#define _LIB_MATROID_INTERSECTION_V2
#include <bits/stdc++.h>
#include "EdgeFinder.cpp"
#include "../../utils/FastQueue.cpp"
#include "../../Lambda.cpp"

namespace lib {
template<typename M1, typename M2>
struct MatroidIntersection {
  int n;
  M1 m1;
  M2 m2;

  bool rank1 = false, rank2 = false;

  // aux vectors
  vector<int> vI;
  vector<int> I;
  FastQueue<int> q;
  vector<int> dist;

  lambda::Subset sI_;
  lambda::SubsetFilter I_;

  MatroidIntersection() : q(1) { init (); }
  MatroidIntersection(const M1& m1, const M2& m2) : m1(m1), m2(m2), n(m1.size()), q(m1.size()) {
    assert(m1.size() == m2.size());
    n = m1.size();
    init();
  }
  void use_rank(bool i1, bool i2) {
    rank1 = i1, rank2 = i2;
  }
  int size() const { return n; }
  void init() {
    vI.clear();
    vI.reserve(n);
    I.assign(n, false);
  }
  void clear() { init(); }
  void setup_set() {
    vI.clear();
    for(int i = 0; i < n; i++) {
      if(I[i]) vI.push_back(i);
    }
    I_ = lambda::SubsetFilter(n, [this](int i) -> bool { return in_I(i); });
    sI_ = I_.subset(n);
  }
  template<typename M>
  std::function<int()> edge_finder(M& mat, int u, int d, bool rank) {
    if(rank)
      return matroid::rank_edge_finder(mat, sI_, I_, u, [this, d](int i) { return dist[i] == d; });
    return matroid::incremental_edge_finder(mat, sI_, I_, u, [this, d](int i) { return dist[i] == d; });
  }
  bool dfs(int u, int du) {
    int v;
    auto forward_edge = edge_finder(m2, u, du - 1, rank2);
    auto backward_edge = edge_finder(m1, u, du - 1, rank1);
    while((v = (du&1) ? backward_edge() : forward_edge()) >= 0) {
      if(v == n) return true;
      dist[v] = -1;
      if(dfs(v, du - 1))
        return I[v] ^= 1, true;
    }
    return false;
  }
  bool augment(bool single = true) {
    setup_set();
    q.clear();
    dist.assign(n+2, -1);
    dist[n+1] = 0;
    q.push(n+1);
    while(dist[n] == -1 && !q.empty()) {
      int u = q.pop();
      auto forward_edge = edge_finder(m1, u, -1, rank1);
      auto backward_edge = edge_finder(m2, u, -1, rank2);
      int v;
      while(dist[n] == -1 && (v = (dist[u]&1) ? backward_edge() : forward_edge()) >= 0) {
        q.push(v), dist[v] = dist[u]+1;
      }
    }
    if(dist[n] == -1) return false;
    while(dfs(n, dist[n])) {
      setup_set();
      if(single) break;
    }
    return true;
  }
  vector<int> solve() {
    m1.clear(), m2.clear();
    for(int i = 0; i < n; i++) {
      if(m1.check(i) && m2.check(i)) {
        m1.add(i), m2.add(i), I[i] = true;
      }
    }
    while(augment(false));
    return I;
  }
  int cardinality() const {
    int res = 0;
    for(int i = 0; i < n; i++)
      res += I[i];
    return res;
  }
  bool in_I(int i) const {
    return I[i];
  }
  const vector<int>& get_I() const {
    return I;
  }
};

template<typename M1, typename M2>
shared_ptr<MatroidIntersection<M1, M2>> make_matroid_intersection(const M1& m1, const M2& m2) {
  return make_shared<MatroidIntersection<M1, M2>>(m1, m2);
}
} // namespace lib

#endif
#line 1 "matroid/v2/MatroidIntersection.cpp"


#include <bits/stdc++.h>
#line 1 "matroid/v2/EdgeFinder.cpp"


#line 1 "matroid/v2/Matroid.cpp"


#line 1 "Lambda.cpp"


#line 1 "Traits.cpp"


#line 4 "Traits.cpp"

namespace lib {
using namespace std;
namespace traits {

template <typename...> struct make_void { using type = void; };

template <typename... T> using void_t = typename make_void<T...>::type;

/// keep caide
template <typename Iterator>
using IteratorCategory = typename iterator_traits<Iterator>::iterator_category;

/// keep caide
template <typename Container>
using IteratorCategoryOf = IteratorCategory<typename Container::iterator>;

/// keep caide
template <typename Iterator>
using IteratorValue = typename iterator_traits<Iterator>::value_type;

/// keep caide
template <typename Container>
using IteratorValueOf = IteratorValue<typename Container::iterator>;

/// keep caide
template <typename Iterator>
using IsRandomIterator =
    is_base_of<random_access_iterator_tag, IteratorCategory<Iterator>>;

/// keep caide
template <typename Iterator>
using IsInputIterator =
    is_base_of<input_iterator_tag, IteratorCategory<Iterator>>;

/// keep caide
template <typename Iterator>
using IsBidirectionalIterator =
    is_base_of<bidirectional_iterator_tag, IteratorCategory<Iterator>>;

/// keep caide
template <typename Container>
using HasRandomIterator =
    is_base_of<random_access_iterator_tag, IteratorCategoryOf<Container>>;

/// keep caide
template <typename Container>
using HasInputIterator =
    is_base_of<input_iterator_tag, IteratorCategoryOf<Container>>;

/// keep caide
template <typename Container>
using HasBidirectionalIterator =
    is_base_of<bidirectional_iterator_tag, IteratorCategoryOf<Container>>;
} // namespace traits
} // namespace lib


#line 5 "Lambda.cpp"

namespace lib {
  using namespace std;
namespace lambda {
  using namespace traits;

const auto identity = [](int i) -> int { return i; };
const auto all = [](int i) -> bool { return true; };
const auto none = [](int i) -> bool { return false; };

auto first_n(int n) {
  return [n](int i) -> bool { return i < n; };
}

template<typename F, typename I = int>
using ValueType = decltype(declval<F>()(declval<I>()));

template<typename T>
struct Map {
  std::function<T(int)> f;
  Map() {}
  template<typename F>
  Map(const F& f_) : f(f_) {}
  T operator()(int i) const {
    return f(i);
  }
};

struct Subset;

template<typename T>
struct SubsetMap : Map<T> {
  using Map<T>::operator();
  using Map<T>::f;

  int n;
  SubsetMap() : Map<T>(), n(0) {}
  template<typename F>
  SubsetMap(int n, F && f_) : Map<T>(f_), n(n) {}
  int size() const { return n; }
  int count() const {
    int cnt = 0;
    for(int i = 0; i < n; i++)
      cnt += f(i) != 0;
    return cnt;
  }
  vector<T> operator()() const {
    vector<T> res(n);
    for(int i = 0; i < n; i++)
      res[i] = f(i);
    return res;
  }

  Subset as_subset() const;

  template<typename U = T,
           enable_if_t<is_same<U, bool>::value>* = nullptr>
  SubsetMap<T> operator!() const {
    return SubsetMap<T>(n, [f=f](int i) { return !f(i); });
  }

  template<typename U = T,
           enable_if_t<is_same<U, bool>::value>* = nullptr>
  SubsetMap<T> operator|(const SubsetMap<T>& rhs) const {
    return SubsetMap<T>(n, [f=f, g=rhs.f](int i) { return f(i) || g(i); });
  }

  SubsetMap<T> operator+(const SubsetMap<T>& rhs) const {
    int N = size() + rhs.size();
    return SubsetMap<T>(N, [n=n, f=f, g=rhs.f](int i) {
      return i >= n ? g(i - n) : f(i);
    });
  }

  SubsetMap<T> operator*(const SubsetMap<T>& rhs) const {
    return SubsetMap<T>(n, [f=f, g=rhs.f](int i) {
      return f(g(i));
    });
  }
};

struct Subset {
  mutable vector<int> map;
  Subset() {}
  Subset(const vector<int>& map_) : map(map_) {
  }
  void add(int i) {
    map.push_back(i);
  }
  void pop() { map.pop_back(); }
  void clear() { map.clear(); }
  int size() const { return map.size(); }
  int operator()(int i) const { return map[i]; }
  vector<int> items() const { return map; }

  template<typename F>
  SubsetMap<ValueType<F>> take_from(F && g) const {
    using T = ValueType<F>;
    auto map_ = map;
    return SubsetMap<T>(map.size(), [g, map_](int i) -> T {
      return g(map_[i]);
    });
  }

  Subset take_subset(const Subset& s) const {
    vector<int> res;
    for(int i : items()) {
      res.push_back(s(i));
    }
    return Subset(res);
  }

  SubsetMap<int> take_indices() const {
    return take_from(identity);
  }

  SubsetMap<int> take_inverse(int def = -1) const {
    int n = 0;
    auto it = max_element(map.begin(), map.end());
    if(it != map.end()) n = *it + 1;
    vector<int> inv(n, def);
    for(int i = 0; i < map.size(); i++)
      inv[map[i]] = i;
    return SubsetMap<int>(n, [inv](int i) -> int {
      return inv[i];
    });
  }

  void sort() const {
    std::sort(map.begin(), map.end());
  }

  Subset operator|(const Subset& rhs) const {
    sort();
    rhs.sort();
    vector<int> res;
    res.reserve(size() + rhs.size());
    merge(map.begin(), map.end(), rhs.map.begin(), rhs.map.end(), back_inserter(res));
    auto it = unique(res.begin(), res.end());
    res.resize(it - res.begin());
    return res;
  }
};

template<>
struct Map<bool> {
    std::function<bool(int)> f;
    Map() {}
    template<typename F>
    Map(const F& f_) : f(f_) {}
    bool operator()(int i) const {
      return f(i);
    }

    template <
      typename Iterator,
      typename enable_if<IsInputIterator<Iterator>::value>::type * = nullptr>
    vector<IteratorValue<Iterator>> operator()(Iterator begin, Iterator end) const {
      vector<IteratorValue<Iterator>> res;
      int i = 0;
      for(auto it = begin; it != end; ++it, ++i) {
        if(f(i)) res.push_back(*it);
      }
      return res;
    }
    template <
      typename Container,
      typename enable_if<HasInputIterator<Container>::value>::type * = nullptr>
    vector<IteratorValueOf<Container>> operator()(const Container& c) const {
      return (*this)(c.begin(), c.end());
    }

    Subset subset(int n) const {
      Subset map;
      for(int i = 0; i < n; i++)
        if(f(i)) map.add(i);
      return map;
    }

    template<typename F>
    SubsetMap<ValueType<F>> subset(int n, F && g) const {
      return subset(SubsetMap<ValueType<F>>(n, g));
    }

    template<typename T>
    SubsetMap<T> subset(const SubsetMap<T>& g) const {
      return subset(g.size()).take_from(g);
    }
};

namespace {
template<typename T,
         enable_if_t<is_same<T, bool>::value>* = nullptr>
Subset as_subset_(const SubsetMap<T>& rhs) {
  Subset map;
  for(int i = 0; i < rhs.size(); i++)
    if(rhs(i)) map.add(i);
  return map;
}
template<typename T,
         enable_if_t<!is_same<T, bool>::value>* = nullptr>
Subset as_subset_(const SubsetMap<T>& rhs) {
  Subset map;
  for(int i = 0; i < rhs.size(); i++)
    map.add(rhs(i));
  return map;
}
}


template<typename T>
Subset SubsetMap<T>::as_subset() const {
  return as_subset_(*this);
  
}

using Filter = Map<bool>;
using SubsetFilter = SubsetMap<bool>;

template<typename T>
SubsetMap<T> from_vector(const vector<T>& v) {
  return SubsetMap<T>(v.size(), [v](int i) -> T {
    return v[i];
  });
}

template<typename U, typename F, typename T = ValueType<F, U>>
SubsetMap<T> map_from_vector(const vector<U>& v, const F& f) {
  return SubsetMap<T>(v.size(), [v, f](int i) -> T {
    return f(v[i]);
  });
}

template<typename T>
SubsetFilter filter_from_vector(const vector<T>& v) {
  return SubsetFilter(v.size(), [v](int i) -> bool {
    return v[i];
  });
}

template<typename T>
SubsetFilter filter_from_sparse_vector(const vector<T>& v) {
  return SubsetFilter(v.size(), [v](int i) -> bool {
    return v[i];
  });
}
} // namespace lambda
} // namespace lib


#line 5 "matroid/v2/Matroid.cpp"

namespace lib {
  using namespace std;
struct Matroid {
  int matroid_size_;
  Matroid() {}
  Matroid(int n) : matroid_size_(n) {}
  void set_ground(int n) { matroid_size_ = n; }
  int size() const { return matroid_size_; }
  virtual int rank(const lambda::Subset&, const lambda::SubsetFilter&) = 0;
  virtual void clear() = 0;
  virtual void add(int i) = 0;
  virtual bool check(int i) = 0;

  int rank() {
    lambda::SubsetFilter f(size(), lambda::all);
    return rank(f.as_subset(), f);
  }

  vector<int> basis(const lambda::Subset& s) {
    clear();
    vector<int> res;
    for(int i : s.items()) {
      if(check(i)) {
        res.push_back(i);
        add(i);
      }
    }
    return res;
  }
  vector<int> basis() {
    return basis(lambda::Filter(lambda::all).subset(size()));
  }
};

struct IncrementalMatroid : Matroid {
  int rank(const lambda::Subset& s, const lambda::SubsetFilter&) override {
    clear();
    int ans = 0;
    for(int i : s.items())
      if(check(i)) add(i), ans++;
    return ans;
  }
};

struct RankMatroid : Matroid {
  lambda::Subset sI;
  vector<int> vI;
  void clear() override { vI.assign(size(), 0), sI.clear(); }
  void add(int i) override { vI[i] = true, sI.add(i); }
  bool check(int i) override {
    if(vI[i]) return true;
    vI[i] = true;
    sI.add(i);
    bool ok = rank(sI, lambda::filter_from_sparse_vector(vI)) >= sI.size();
    vI[i] = false;
    sI.pop();
    return ok;
  }
};

namespace matroid {
template<typename M>
using IsRank = is_base_of<RankMatroid, M>;

template<typename M>
using IsIncremental = is_base_of<IncrementalMatroid, M>;
} // namespace matroid
} // namespace lib


#line 6 "matroid/v2/EdgeFinder.cpp"

namespace lib {
  using namespace std;
namespace matroid {

template<typename M, typename F>
auto incremental_edge_finder(
  M& m,
  const lambda::Subset& sI,
  const lambda::SubsetFilter& I,
  int v,
  F && test) {
  return [&, v, test, done=0, ans=vector<int>()] () mutable {
    if(v < I.size() && !I(v)) {
      // CASE 1: v is an element not in IS.
      // In this case, should add v and remove a neighbor.
      m.clear();
      // First of all, add v.
      if(!m.check(v)) return -1;
      m.add(v);
      // Now add IS elements that aren't in B. These can't be removed.
      for(int i : sI.items()) {
        if(test(i)) continue;
        if(!m.check(i)) return -1;
        m.add(i);
      }
      // Finally, add IS elements that ARE in B. 
      for(int i : sI.items()) {
        if(!test(i)) continue;
        if(!m.check(i)) {
          // Introducing i and every element that comes next
          // makes this a circuit, that can be made independent by removing i.
          return i;
        }
        m.add(i);
      }
      // Element can be added directly, with no exchange.
      return I.size();
    }
    // CASE 2: v is source or an element in IS.
    if(!done) {
      // In this case, we should try adding elements after removing v.
      m.clear();
      for(int i : sI.items())
        if(i != v) m.add(i);
      for(int i = 0; i < I.size(); i++)
        if(!I(i) && test(i) && m.check(i))
          ans.push_back(i);
    }
    if(done < ans.size()) return ans[done++];
    return -1;
  };
}

template<typename M, typename F>
auto rank_edge_finder(
  M& m,
  const lambda::Subset& sI,
  const lambda::SubsetFilter& I,
  int v,
  F && test) {

  // Fast SubsetFilter.
  static vector<int> mask(1);
  int n = mask.size();
  while(n < I.size()) n *= 2;
  mask.assign(n, 0);

  auto filter = lambda::SubsetFilter(I.size(), [](int i) {
    return mask[i];
  });
  const static auto subset_mask = [](const lambda::Subset& s) {
    for(int i : s.items())
      mask[i] = true;
  };
  const static auto clear_mask = [](const lambda::Subset& s) {
    for(int i : s.items())
      mask[i] = false;
  };

  return [&, v, test, filter, sub=lambda::Subset()] () mutable {
    vector<int> need, extra;
    if(v < I.size() && !I(v)) {
      // CASE 1: v NOT in IS.
      // `need` will be v + elements that are in IS
      // but are not in B. Thus, they can't be part of
      // an exchange.
      // `extra` will be elements of IS that are in B.
      need.push_back(v);
      for(auto i : sI.items())
        if(!test(i)) need.push_back(i);
        else extra.push_back(i);

      auto check = [&](int mid) {
        need.insert(need.end(), extra.begin(), extra.begin() + mid);
        swap(sub.map, need);
        subset_mask(sub);
        int res = m.rank(sub, filter);
        clear_mask(sub);
        swap(sub.map, need);
        need.erase(need.end() - mid, need.end());
        return res == need.size() + mid;
      };

      // Binary search on element that makes up the circuit.
      if(!check(0)) return -1;
      if(check(extra.size())) return I.size();
      int l = 0, r = extra.size() + 1;
      while(l < r) {
        int mid = (l+r)/2;
        if(!check(mid))
          r = mid;
        else l = mid + 1;
      }
      if(l == extra.size() + 1) return I.size();
      return extra[l-1];
    }

    // CASE 2: v in IS.
    for(int i : sI.items())
      if(i != v) need.push_back(i);
    for(int i = 0; i < I.size(); i++)
      if(!I(i) && test(i)) extra.push_back(i);
    auto check = [&](int l, int r) {
      need.insert(need.end(), extra.begin() + l, extra.begin() + r);
      swap(sub.map, need);
      subset_mask(sub);
      int res = m.rank(sub, filter);
      clear_mask(sub);
      swap(sub.map, need);
      need.erase(need.end() - (r - l), need.end());
      return res > need.size();
    };

    int l = 0, r = extra.size();
    if(!check(l, r)) return -1;
    while(l < r) {
      int mid = (l+r)/2;
      if(check(l, mid+1))
        r = mid;
      else l = mid + 1;
    }
    return extra[l];
  };
}

} // namespace matroid
} // namespace lib


#line 1 "utils/FastQueue.cpp"


#line 4 "utils/FastQueue.cpp"

namespace lib {
  using namespace std;
template<typename T>
struct FastQueue {
  vector<T> v;
  int L = 0, R = 0;
  FastQueue(int cap) : v(cap) {}

  void push(const T& no) {
    if(R >= v.size()) v.emplace_back();
    v[R++] = no;
  }
  T& front() {
    return v[L];
  }
  T front() const {
    return v[L];
  }
  T pop() {
    return v[L++];
  }
  bool empty() const {
    return L >= R;
  }
  int size() const {
    return max(R - L, 0);
  }
  void clear() {
    L = 0, R = 0;
  }
};
} // namespace lib


#line 7 "matroid/v2/MatroidIntersection.cpp"

namespace lib {
template<typename M1, typename M2>
struct MatroidIntersection {
  int n;
  M1 m1;
  M2 m2;

  bool rank1 = false, rank2 = false;

  // aux vectors
  vector<int> vI;
  vector<int> I;
  FastQueue<int> q;
  vector<int> dist;

  lambda::Subset sI_;
  lambda::SubsetFilter I_;

  MatroidIntersection() : q(1) { init (); }
  MatroidIntersection(const M1& m1, const M2& m2) : m1(m1), m2(m2), n(m1.size()), q(m1.size()) {
    assert(m1.size() == m2.size());
    n = m1.size();
    init();
  }
  void use_rank(bool i1, bool i2) {
    rank1 = i1, rank2 = i2;
  }
  int size() const { return n; }
  void init() {
    vI.clear();
    vI.reserve(n);
    I.assign(n, false);
  }
  void clear() { init(); }
  void setup_set() {
    vI.clear();
    for(int i = 0; i < n; i++) {
      if(I[i]) vI.push_back(i);
    }
    I_ = lambda::SubsetFilter(n, [this](int i) -> bool { return in_I(i); });
    sI_ = I_.subset(n);
  }
  template<typename M>
  std::function<int()> edge_finder(M& mat, int u, int d, bool rank) {
    if(rank)
      return matroid::rank_edge_finder(mat, sI_, I_, u, [this, d](int i) { return dist[i] == d; });
    return matroid::incremental_edge_finder(mat, sI_, I_, u, [this, d](int i) { return dist[i] == d; });
  }
  bool dfs(int u, int du) {
    int v;
    auto forward_edge = edge_finder(m2, u, du - 1, rank2);
    auto backward_edge = edge_finder(m1, u, du - 1, rank1);
    while((v = (du&1) ? backward_edge() : forward_edge()) >= 0) {
      if(v == n) return true;
      dist[v] = -1;
      if(dfs(v, du - 1))
        return I[v] ^= 1, true;
    }
    return false;
  }
  bool augment(bool single = true) {
    setup_set();
    q.clear();
    dist.assign(n+2, -1);
    dist[n+1] = 0;
    q.push(n+1);
    while(dist[n] == -1 && !q.empty()) {
      int u = q.pop();
      auto forward_edge = edge_finder(m1, u, -1, rank1);
      auto backward_edge = edge_finder(m2, u, -1, rank2);
      int v;
      while(dist[n] == -1 && (v = (dist[u]&1) ? backward_edge() : forward_edge()) >= 0) {
        q.push(v), dist[v] = dist[u]+1;
      }
    }
    if(dist[n] == -1) return false;
    while(dfs(n, dist[n])) {
      setup_set();
      if(single) break;
    }
    return true;
  }
  vector<int> solve() {
    m1.clear(), m2.clear();
    for(int i = 0; i < n; i++) {
      if(m1.check(i) && m2.check(i)) {
        m1.add(i), m2.add(i), I[i] = true;
      }
    }
    while(augment(false));
    return I;
  }
  int cardinality() const {
    int res = 0;
    for(int i = 0; i < n; i++)
      res += I[i];
    return res;
  }
  bool in_I(int i) const {
    return I[i];
  }
  const vector<int>& get_I() const {
    return I;
  }
};

template<typename M1, typename M2>
shared_ptr<MatroidIntersection<M1, M2>> make_matroid_intersection(const M1& m1, const M2& m2) {
  return make_shared<MatroidIntersection<M1, M2>>(m1, m2);
}
} // namespace lib
Back to top page