cp-includes

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

View the Project on GitHub rsalesc/cp-includes

:heavy_check_mark: tests/yosupo/2sat.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/two_sat"

#include <bits/stdc++.h>
#include "TwoSat.cpp"
#define int long long
using namespace std;
 
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define ms(v, x) memset((v), (x), sizeof(v))
#define all(v) (v).begin(), (v).end()
#define ff first
#define ss second
#define iopt ios::sync_with_stdio(false); cin.tie(0)
#define untie(p, a, b) decltype(p.first) a = p.first, decltype(p.second) b = p.second
 
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int power(int x, int p, int MOD) {
    if(p == 0) return 1%MOD;
    if(p == 1) return x%MOD;
    int res = power(x, p/2, MOD);
    res = (long long)res*res%MOD;
    if(p&1) res = (long long)res*x%MOD;
    return res;
}
 
typedef pair<int, int> ii;
typedef long double LD;
typedef vector<int> vi;

using namespace lib;

int32_t main(){
    // Scanner sc(stdin);
    // Printer pr(stdout);
    iopt;
    string _;
    int n, m;
    cin >> _ >> _ >> n >> m;

    graph::TwoSat sat(n + 1);

    for(int i = 0; i < m; i++) {
      int a, b, _;
      cin >> a >> b >> _;
      sat.or_clause(VAR(a), VAR(b));
    }

    if(!sat.solve()) {
      cout << "s UNSATISFIABLE" << endl;
      return 0;
    }
    cout << "s SATISFIABLE" << endl;
    cout << "v ";
    for(int i = 1; i <= n; i++) {
      if(sat.get(i)) cout << i << " ";
      else cout << -i << " ";
    }
    cout << 0 << endl;
}
#line 1 "tests/yosupo/2sat.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/two_sat"

#include <bits/stdc++.h>
#line 1 "TwoSat.cpp"


#line 1 "Graph.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 1 "utils/Wrappers.cpp"


#line 4 "utils/Wrappers.cpp"

namespace lib {
using namespace std;
namespace graph {
template <typename T> struct Edge {
  const int from, to;
  T data;
};

template <> struct Edge<void> { const int from, to; };

template <typename T> struct VertexWrapper { T data; };

template <> struct VertexWrapper<void> {};
} // namespace graph
} // namespace lib


#line 6 "Graph.cpp"

namespace lib {
using namespace std;
namespace graph {
template <typename V = void, typename E = void, bool Directed = false>
struct GraphImpl {
  typedef GraphImpl<V, E> self_type;
  typedef vector<vector<int>> adj_list;
  typedef Edge<E> edge_type;
  typedef VertexWrapper<V> vertex_type;

  const static bool directed = Directed;

  vector<edge_type> edges;
  adj_list adj;

  vector<vertex_type> vertices;

  class iterator {
  public:
    typedef iterator self_type;
    typedef edge_type value_type;
    typedef edge_type &reference;
    typedef edge_type *pointer;
    typedef std::forward_iterator_tag iterator_category;
    typedef int difference_type;
    iterator(vector<int> *adj, vector<edge_type> *edges, int ptr = 0)
        : adj_(adj), edges_(edges), ptr_(ptr) {}
    self_type operator++() {
      ptr_++;
      return *this;
    }
    self_type operator++(int junk) {
      self_type i = *this;
      ptr_++;
      return i;
    }
    reference operator*() { return (*edges_)[(*adj_)[ptr_]]; }
    pointer operator->() { return &(*edges_)[(*adj_)[ptr_]]; }
    bool operator==(const self_type &rhs) const {
      return adj_ == rhs.adj_ && ptr_ == rhs.ptr_;
    }
    bool operator!=(const self_type &rhs) const { return !(*this == rhs); }

  private:
    vector<int> *adj_;
    vector<edge_type> *edges_;
    int ptr_;
  };

  class const_iterator {
  public:
    typedef const_iterator self_type;
    typedef edge_type value_type;
    typedef edge_type &reference;
    typedef edge_type *pointer;
    typedef std::forward_iterator_tag iterator_category;
    typedef int difference_type;
    const_iterator(vector<int> *adj, vector<edge_type> *edges, int ptr = 0)
        : adj_(adj), edges_(edges), ptr_(ptr) {}
    self_type operator++() {
      ptr_++;
      return *this;
    }
    self_type operator++(int junk) {
      self_type i = *this;
      ptr_++;
      return i;
    }
    const value_type &operator*() { return (*edges_)[(*adj_)[ptr_]]; }
    const value_type *operator->() { return &(*edges_)[(*adj_)[ptr_]]; }
    bool operator==(const self_type &rhs) const {
      return adj_ == rhs.adj_ && ptr_ == rhs.ptr_;
    }
    bool operator!=(const self_type &rhs) const { return !(*this == rhs); }

  private:
    vector<int> *adj_;
    vector<edge_type> *edges_;
    int ptr_;
  };

  struct iterable {
    vector<int> *adj_;
    vector<edge_type> *edges_;

    iterable(vector<int> *adj, vector<edge_type> *edges)
        : adj_(adj), edges_(edges) {}

    inline iterator begin() { return iterator(adj_, edges_); }
    inline iterator end() { return iterator(adj_, edges_, adj_->size()); }

    inline const_iterator cbegin() const {
      return const_iterator(adj_, edges_);
    }
    inline const_iterator cend() const {
      return const_iterator(adj_, edges_, adj_->size());
    }

    inline const_iterator begin() const { return cbegin(); }
    inline const_iterator end() const { return cend(); }

    inline edge_type &operator[](int i) { return (*edges_)[(*adj_)[i]]; }
    inline const edge_type &operator[](int i) const {
      return (*edges_)[(*adj_)[i]];
    }

    inline int index(int i) const { return (*adj_)[i]; }
    inline int size() const { return adj_->size(); }
  };

  GraphImpl() {}

  template <typename S = V,
            typename enable_if<is_void<S>::value>::type * = nullptr>
  GraphImpl(size_t n) : adj(n) {}

  template <typename S = V,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  GraphImpl(size_t n) : adj(n), vertices(n) {}

  inline iterable n_edges(int i) { return iterable(&adj[i], &edges); }
  inline const iterable n_edges(int i) const {
    return iterable(const_cast<vector<int> *>(&adj[i]),
                    const_cast<vector<edge_type> *>(&edges));
  }
  inline int degree(int i) const { return adj[i].size(); }

  inline int size() const { return adj.size(); }
  inline int edge_size() const { return edges.size(); }
  inline edge_type &edge(int i) { return edges[i]; }
  inline edge_type edge(int i) const { return edges[i]; }

  inline vector<edge_type> all_edges() const { return edges; }

  template <typename S = V,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  inline S &vertex(int i) {
    return vertices[i];
  }

  template <typename S = V,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  inline V vertex(int i) const {
    return vertices[i];
  }

  template <typename S = V,
            typename enable_if<is_void<S>::value>::type * = nullptr>
  inline void add_vertex() {
    adj.emplace_back();
  }

  template <typename S = V,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  inline S &add_vertex() {
    adj.emplace_back();
    return vertices.emplace_back().data;
  }

  template <typename S = E,
            typename enable_if<is_void<S>::value>::type * = nullptr>
  inline void add_edge_(int u, int v) {
    adj[u].push_back(edges.size());
    edges.push_back({u, v});
  }

  template <typename S = E,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  inline S &add_edge_(int u, int v) {
    adj[u].push_back(edges.size());
    edges.push_back({u, v});
    return edges.back().data;
  }

  void add_2edge(int u, int v) {
    add_edge_(u, v);
    add_edge_(v, u);
  }

  template <typename S = E,
            typename enable_if<!is_void<S>::value>::type * = nullptr>
  inline void add_2edge(int u, int v, const S &data) {
    add_edge_(u, v) = data;
    add_edge_(v, u) = data;
  }

  template <typename S = E,
            typename enable_if<is_void<S>::value && Directed>::type * = nullptr>
  inline void add_edge(int u, int v) {
    adj[u].push_back(edges.size());
    edges.push_back({u, v});
  }

  template <typename S = E,
            typename enable_if<!is_void<S>::value && Directed>::type * = nullptr>
  inline S &add_edge(int u, int v) {
    adj[u].push_back(edges.size());
    edges.push_back({u, v});
    return edges.back().data;
  }
};

template<typename V = void, typename E = void>
using Graph = GraphImpl<V, E, false>;

template<typename V = void, typename E = void>
using DirectedGraph = GraphImpl<V, E, true>;

template <typename V = void, typename E = void>
struct RootedForest : public DirectedGraph<V, E> {
  typedef RootedForest<V, E> self_type;
  using typename DirectedGraph<V, E>::adj_list;
  using typename DirectedGraph<V, E>::edge_type;
  using DirectedGraph<V, E>::DirectedGraph;
  using DirectedGraph<V, E>::adj;
  using DirectedGraph<V, E>::edge;
  vector<int> p, pe;

  void build_parents() {
    if ((int)p.size() == this->size())
      return;

    int n = this->size();
    stack<int> st;
    vector<bool> vis(n);
    p.assign(n, -1), pe.assign(n, -1);
    for (int i = 0; i < n; i++) {
      if (!vis[i]) {
        st.push(i);
        vis[i] = true;
        while (!st.empty()) {
          int u = st.top();
          st.pop();

          for (int k : adj[u]) {
            int v = edge(k).to;
            vis[v] = true;
            st.push(v), pe[v] = k, p[v] = u;
          }
        }
      }
    }
  }

  inline int parent(int i) const {
    const_cast<self_type *>(this)->build_parents();
    return p[i];
  }

  inline bool is_root(int i) const { return parent(i) != -1; }

  inline edge_type &parent_edge(int i) {
    build_parents();
    return edge(pe[i]);
  }
  inline edge_type &parent_edge(int i) const {
    const_cast<self_type *>(this)->build_parents();
    return edge(pe[i]);
  }

  vector<int> roots() const {
    vector<int> res;
    const_cast<self_type *>(this)->build_parents();
    int n = this->size();

    for (int i = 0; i < n; i++)
      if (p[i] == -1)
        res.push_back(i);
    return res;
  }
};

template <typename V = void, typename E = void>
struct RootedTree : public RootedForest<V, E> {
  using typename RootedForest<V, E>::adj_list;
  int root;

  RootedTree(int n, int root) : RootedForest<V, E>(n) {
    assert(n > 0);
    assert(root < n);
    this->root = root;
  }

  RootedTree(const adj_list &adj, int root) : RootedForest<V, E>(adj) {
    assert(adj.size() > 0);
    assert(root < adj.size());
    this->root = root;
  }
};

namespace builders {
namespace {
template <typename F, typename G>
void dfs_rooted_forest(F &forest, const G &graph, int u, vector<bool> &vis) {
  vis[u] = true;
  for (const auto &ed : graph.n_edges(u)) {
    int v = ed.to;
    if (!vis[v]) {
      forest.add_edge(u, v);
      dfs_rooted_forest(forest, graph, v, vis);
    }
  }
}
} // namespace

template <typename A, typename B>
RootedForest<A, B> make_rooted_forest(const Graph<A, B> &graph,
                                      const vector<int> &roots) {
  RootedForest<A, B> res(graph.size());
  vector<bool> vis(graph.size());
  for (int i : roots)
    if (!vis[i])
      dfs_rooted_forest(res, graph, i, vis);
  for (int i = 0; i < graph.size(); i++)
    if (!vis[i])
      dfs_rooted_forest(res, graph, i, vis);
  return res;
}
} // namespace builders
} // namespace graph
} // namespace lib


#line 5 "TwoSat.cpp"

namespace lib {
using namespace std;
namespace graph {
#define POS(x) (2*(x))
#define NEG(x) (2*(x)+1)
#define VAR(x) ((x) < 0 ? NEG(-(x)) : POS(x))

// TODO: reuse graph structure and extract tarjan
struct TwoSat {
  int n, sz;
  vector<vector<int>> adj;
  
  int tempo, cnt;
  vector<int> low, vis, from;
  stack<int> st;
  vector<bool> res;

  TwoSat(int n) : n(n), adj(2*n){}

  int add_dummy() { 
    int res = adj.size();
    for(int i = 0; i < 2; i++)
      adj.push_back(vector<int>());
    return res;
  }

  int convert(int x) const { return 2*x; }
  void add_edge(int a, int b) { adj[a].push_back(b); }
  void or_clause(int a, int b){
    add_edge(a^1, b);
    add_edge(b^1, a);
  }

  void implication_clause(int a, int b){
    or_clause(a^1, b);
  }

  void literal_clause(int x) { or_clause(x, x); }
  void and_clause(int a, int b){
    literal_clause(a);
    literal_clause(b);
  }

  void xor_clause(int a, int b){
    or_clause(a, b);
    or_clause(a^1, b^1);
  }

  void nand_clause(int a, int b){
    or_clause(a^1, b^1);
  }

  void nor_clause(int a, int b){
    literal_clause(a^1);
    literal_clause(b^1);
  }

  void equals(int a, int b){
    implication_clause(a, b);
    implication_clause(b, a);
  }

  void max_one_clause(const vector<int> & v){
    vector<int> p;
    for(int i = 0; i < v.size(); i++)
      p.push_back(add_dummy());

    for(int i = 0; i < v.size(); i++){
      implication_clause(v[i], p[i]);
      if(i+1 < v.size()){
        implication_clause(p[i], p[i+1]);
        implication_clause(p[i], v[i+1]^1);
      }
    }
  }

  void clear(){
    for(int i = 0; i < adj.size(); i++) 
      adj[i].clear();
  }

  void tarjan(int u){
    low[u] = vis[u] = ++tempo;
    st.push(u);

    for(int v : adj[u]){
      if(!vis[v]){
        tarjan(v);
        low[u] = min(low[u], low[v]);
      } else if(vis[v] > 0)
        low[u] = min(low[u], vis[v]);
    }

    if(low[u] == vis[u]){
      int k;
      do{
        k = st.top();
        st.pop();
        from[k] = cnt;
        vis[k] = -1;
      } while(k != u);
      cnt++;
    }
  }

  bool solve(){
    sz = adj.size();
    assert(sz%2 == 0);

    low.assign(sz, 0);
    vis.assign(sz, 0);
    tempo = 0;
    cnt = 0;
    from.assign(sz, -1);
    st = stack<int>();
    
    res.assign(n, true);

    for(int i = 0; i < sz; i++)
      if(!vis[i])
        tarjan(i);

    for(int i = 0; i < sz; i += 2){
      if(from[i] == from[i^1]) return false;
      else if(from[i] > from[i^1] && (i>>1) < n)
        res[i>>1] = false;
    }

    return true;
  }

  bool get(int i) const { return res[i]; }
};
} // namespace graph
} // namespace lib


#line 5 "tests/yosupo/2sat.test.cpp"
#define int long long
using namespace std;
 
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define ms(v, x) memset((v), (x), sizeof(v))
#define all(v) (v).begin(), (v).end()
#define ff first
#define ss second
#define iopt ios::sync_with_stdio(false); cin.tie(0)
#define untie(p, a, b) decltype(p.first) a = p.first, decltype(p.second) b = p.second
 
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int power(int x, int p, int MOD) {
    if(p == 0) return 1%MOD;
    if(p == 1) return x%MOD;
    int res = power(x, p/2, MOD);
    res = (long long)res*res%MOD;
    if(p&1) res = (long long)res*x%MOD;
    return res;
}
 
typedef pair<int, int> ii;
typedef long double LD;
typedef vector<int> vi;

using namespace lib;

int32_t main(){
    // Scanner sc(stdin);
    // Printer pr(stdout);
    iopt;
    string _;
    int n, m;
    cin >> _ >> _ >> n >> m;

    graph::TwoSat sat(n + 1);

    for(int i = 0; i < m; i++) {
      int a, b, _;
      cin >> a >> b >> _;
      sat.or_clause(VAR(a), VAR(b));
    }

    if(!sat.solve()) {
      cout << "s UNSATISFIABLE" << endl;
      return 0;
    }
    cout << "s SATISFIABLE" << endl;
    cout << "v ";
    for(int i = 1; i <= n; i++) {
      if(sat.get(i)) cout << i << " ";
      else cout << -i << " ";
    }
    cout << 0 << endl;
}
Back to top page