This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include "parks.h"
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define debug(...) //ignore
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef long double ld;
namespace LCT {
  /**
   * Description: Link-Cut Tree with possibility to augment.
   * \texttt{sz} is for path queries; 
   * \texttt{sub}, \texttt{vsub} are for subtree queries. \texttt{x->access()} 
   * brings \texttt{x} to the top of splay tree and propagates it (\textbf{call it!});
   * the left subtree will be
   * the path from \texttt{x} to the root and the right subtree will be empty. 
   * Then $\texttt{sub} = $ size of connected component
   * and $\texttt{vsub} = $ number of nodes below \texttt{x}.
   * \texttt{x->makeRoot()} ``rotates'' the tree so that \texttt{x} is root.
   * Use \texttt{x->makeRoot(), y->access(), y->sum} for path queries.
   * Time: O(\log N)
   * Usage: vector<sn> lct; rep(i,0,n) lct[i]=new snode(i); link(lct[0],lct[2],1); cut(lct[2],lct[0]);
   * Author: benq
   * Source: Dhruv Rohatgi, Eric Zhang, Benq
   * https://sites.google.com/site/kc97ble/container/splay-tree/splaytree-cpp-3
   * https://codeforces.com/blog/entry/67637
   * Status: tested on problems...
   */
  typedef struct snode* sn;
  struct snode { //////// VARIABLES
    sn p, c[2]; // parent, children
    bool flip = 0; // subtree flipped or not
    int val = -1, sz; // value in node, # nodes in current splay tree
    int sub, vsub = 0; // vsub stores sum of virtual children
    int max_val = -1;
    snode(int _val) : val(_val) {
      p = c[0] = c[1] = NULL; calc(); }
    friend int getSz(sn x) { return x?x->sz:0; }
    friend int get_max_val(sn x) { return x?x->max_val:-1; }
    friend int getSub(sn x) { return x?x->sub:0; }
    void prop() { // lazy prop
      if (!flip) return;
      swap(c[0],c[1]); flip = 0;
      rep(i,0,2) if (c[i]) c[i]->flip ^= 1;
    }
    void calc() { // recalc vals
      rep(i,0,2) if (c[i]) c[i]->prop();
      sz = 1+getSz(c[0])+getSz(c[1]);
      sub = 1+getSub(c[0])+getSub(c[1])+vsub;
      max_val = max({val, get_max_val(c[0]), get_max_val(c[1])});
    }
    void set(int v) { access(); val = v; calc(); }
    // ============ SPLAY TREE OPERATIONS ==============
    int dir() {
      if (!p) return -2;
      rep(i,0,2) if (p->c[i] == this) return i;
      return -1; // p is path-parent pointer, not same splaytree
    }
    bool isRoot() { return dir() < 0; }  // of splaytree
    friend void setLink(sn x, sn y, int d) {
      if (y) y->p = x;
      if (d >= 0) x->c[d] = y; }
    void rot() { // assume p and p->p propagated
      assert(!isRoot()); int x = dir(); sn pa = p;
      setLink(pa->p, this, pa->dir());
      setLink(pa, c[x^1], x); setLink(this, pa, x^1);
      pa->calc();
    }
    void splay() {
      while (!isRoot() && !p->isRoot()) {
        p->p->prop(), p->prop(), prop();
        dir() == p->dir() ? p->rot() : rot();
        rot();
      }
      if (!isRoot()) p->prop(), prop(), rot();
      prop(); calc();
    }
    sn fbo(int b) { // (optional) find by order
      prop(); int z = getSz(c[0]); // of splay tree
      if (b == z) { splay(); return this; }
      return b < z ? c[0]->fbo(b) : c[1] -> fbo(b-z-1);
    }
    // ============ BASE OPERATIONS ==============
    void access() { // bring this to top of splaytree, propagate
      for (sn v = this, pre = NULL; v; v = v->p) {
        v->splay(); // now switch virtual children
        if (pre) v->vsub -= pre->sub;
        if (v->c[1]) v->vsub += v->c[1]->sub;
        v->c[1] = pre; v->calc(); pre = v;
      }
      splay(); assert(!c[1]); // right subtree is empty
    }
    void makeRoot() { // make root of real tree
      access(); flip ^= 1; access(); assert(!c[0] && !c[1]);
    }
    // ===================== QUERIES =====================
    friend bool connected(sn x, sn y) { return lca(x,y); } 
    friend sn lca(sn x, sn y) {
      if (x == y) return x;
      x->access(), y->access(); if (!x->p) return NULL;
      x->splay(); return x->p?:x;
    }
    int distRoot() { access(); return getSz(c[0]); }
    sn getRoot() { // get (real tree) root of component
      access(); sn a = this; 
      while (a->c[0]) a = a->c[0], a->prop();
      a->access(); return a;
    }
    sn getPar(int b) { // get b-th parent on path to root
      access(); b = getSz(c[0])-b; assert(b >= 0);
      return fbo(b); // can also get min, max on path to root...
    }
    // ================= MODIFICATIONS =====================
    friend void link(sn x, sn y, bool force = 1) {
      assert(!connected(x,y)); // when force = 0,
      if (force) y->makeRoot(); // assumes y has no parent
      else { y->access(); assert(!y->c[0]); }
      x->access(); setLink(y,x,0); y->calc();
    }
    friend void cut(sn y) { // cut from parent
      y->access(); assert(y->c[0]);
      y->c[0]->p = NULL; y->c[0] = NULL; y->calc();
    }
    friend void cut(sn x, sn y) { // if x, y adj in tree
      x->makeRoot(); y->access(); 
      assert(y->c[0] == x && !x->c[0] && !x->c[1]); cut(y);
    }
  };
}
int n = 0; // number of ground elements
struct PartitionMatroid { // partition matroid
  vi cols;
  vector<vi> has_col;
  set<int> unused_cols;
  vi used;
  PartitionMatroid(vi c) : used(n) {
    cols = c;
    int mx = 0;
    for(int c : cols) mx = max(mx,c);
    has_col.resize(mx+1);
    rep(i,0,n) has_col[c[i]].emplace_back(i);
    rep(i,0,sz(has_col)) unused_cols.emplace(i);
  }
  void add(int i) {
    assert(!used[i]);
    assert(unused_cols.count(cols[i]));
    unused_cols.erase(cols[i]);
    used[i] = 1;
  }
  void rem(int i) {
    assert(used[i]);
    assert(!unused_cols.count(cols[i]));
    unused_cols.emplace(cols[i]);
    used[i] = 0;
  }
  int is_free(int b) { return unused_cols.count(cols[b]); }
  vi find_exchangeAB(int a) { // if we remove a, which b can we add?
    assert(used[a]);
    vi res;
    for(int b : has_col[cols[a]]) if(b != a) {
      assert(!used[b]);
      res.emplace_back(b);
    }
    return res;
  }
};
struct GraphicMatroid {
  vi u, v; // (u[i], v[i]) are the edges
  int m; // # graph nodes;
  vi bad, used;
  vector<LCT::sn> lct;
  vector<LCT::sn> lct_ed;
  set<int> used_set;
  GraphicMatroid(vi a, vi b, int m) : u(a), v(b), m(m), bad(n), used(n) {
    lct.resize(m);
    lct_ed.resize(n);
    rep(i,0,m) lct[i] = new LCT::snode(-1);
    rep(i,0,n) lct_ed[i] = new LCT::snode(-1);
  }
  void add(int i) {
    assert(!used[i]);
    used[i] = 1;
    used_set.emplace(i);
    link(lct[u[i]], lct_ed[i]);
    link(lct[v[i]], lct_ed[i]);
  }
  void rem(int i) {
    assert(used[i]);
    used[i] = 0;
    used_set.erase(i);
    cut(lct[u[i]], lct_ed[i]);
    cut(lct[v[i]], lct_ed[i]);
  }
  void clear_bad() {
    fill(all(bad),0);
    for(int i : used_set) lct_ed[i]->set(i);
  }
  void mark_bad(int i) {
    if(bad[i]) return;
    bad[i] = 1;
    lct_ed[i]->set(-1);
  }
  bool is_free(int b) { // can we add b?
    assert(!used[b]);
    return !connected(lct[u[b]], lct[v[b]]);
  }
  int find_exchangeBA(int b) { // if we add b, which a should be removed?
    // just find a single out-edge!
    assert(!used[b]);
    int x = u[b], y = v[b];
    assert(connected(lct[x], lct[y]));
    lct[x]->makeRoot();
    lct[y]->access();
    int res = lct[y]->max_val;
    assert(res == -1 || (!bad[res] && used[res]));
    return res;
  }
  ~GraphicMatroid(){
    rep(i,0,m) delete lct[i];
    rep(i,0,n) delete lct_ed[i];
  }
};
struct MatroidIsec {
  PartitionMatroid& m1;
  GraphicMatroid& m2;
  vi used;
  MatroidIsec(PartitionMatroid& m1, GraphicMatroid& m2) : m1(m1), m2(m2), used(n) {}
  const int inf = 1e9;
  vi layers;
  bool forward() {
    layers.assign(n, inf);
    m2.clear_bad();
    queue<int> q;
    rep(b,0,n) if(m1.is_free(b)) {
      layers[b] = 0;
      q.push(b);
    }
    while(sz(q)) {
      int x = q.front();
      q.pop();
      if(used[x]) {
        int a = x;
        for(int b : m1.find_exchangeAB(a)) if(layers[b] == inf) {
          layers[b] = layers[a]+1;
          q.push(b);
        }
      }
      else {
        int b = x, a;
        if(m2.is_free(b)) return true; // found s,t-path!
        while((a = m2.find_exchangeBA(b)) != -1) {
          assert(layers[a] == inf);
          m2.mark_bad(a);
          layers[a] = layers[b]+1;
          q.push(a);
        }
      }
    }
    return false;
  }
  vi bad, aug;
  void push_flow() {
    bad.assign(n,0);
    m2.clear_bad();
    vi todo;
    rep(i,0,n) if(layers[i] == 0) todo.emplace_back(i);
    for(int b : todo) {
      if(bad[b]) continue;
      if(!m1.is_free(b)) continue;
      aug.clear();
      if(dfs(b)) {
        for(int i : aug) {
          bad[i] = true;
          m2.mark_bad(i);
        }
        for(int i : aug) if(used[i]) {
          m1.rem(i);
          m2.rem(i);
        }
        for(int i : aug) if(!used[i]) {
          m1.add(i);
          m2.add(i);
        }
        for(int i : aug) used[i] = !used[i];
        aug.clear();
      }
    }
  }
  bool dfs(int x) {
    assert(!bad[x]);
    if(used[x]) {
      int a = x;
      for(int b : m1.find_exchangeAB(a)) {
        if(layers[b] != layers[a]+1) continue;
        if(bad[b]) continue;
        if(dfs(b)) {
          aug.emplace_back(a);
          return true;
        }
      }
    }
    else {
      int b = x, a;
      if(m2.is_free(b)) {
        aug.emplace_back(b);
        return true;
      }
      while((a = m2.find_exchangeBA(b)) != -1) {
        m2.mark_bad(a);
        if(layers[a] != layers[b]+1) continue;
        if(dfs(a)) {
          aug.emplace_back(b);
          return true;
        }
      }
    }
    bad[x] = true;
    m2.mark_bad(x);
    return false;
  }
  void solve() {
    debug(used);
    while(forward()) {
      push_flow();
      debug(used);
    }
  }
};
int construct_roads(std::vector<int> x, std::vector<int> y) {
  map<pii,int> to_idx;
  rep(i,0,sz(x)) to_idx[pii(x[i],y[i])] = i;
  vi cols;
  vi u,v;
  auto add = [&](int x, int y, int c){
    ++n;
    u.emplace_back(x);
    v.emplace_back(y);
    cols.emplace_back(c);
  };
  int col = 0;
  map<pii,int> to_col;
  map<int,pii> from_col;
  auto which_col = [&](pii p) {
    if(!to_col.count(p)) {
      to_col[p] = col;
      from_col[col] = p;
      ++col;
    }
    return to_col[p];
  };
  rep(i,0,sz(x)) {
    if(to_idx.count(pii(x[i]+2,y[i]))) {
      int j = to_idx[pii(x[i]+2,y[i])];
      add(i,j,which_col(pii(x[i]+1, y[i]+1)));
      add(i,j,which_col(pii(x[i]+1, y[i]-1)));
    }
    if(to_idx.count(pii(x[i],y[i]+2))) {
      int j = to_idx[pii(x[i],y[i]+2)];
      add(i,j,which_col(pii(x[i]+1, y[i]+1)));
      add(i,j,which_col(pii(x[i]-1, y[i]+1)));
    }
  }
  debug(cols);
  debug(u);
  debug(v);
  PartitionMatroid m1(cols);
  GraphicMatroid m2(u,v,sz(x));
  MatroidIsec mi(m1, m2);
  mi.solve();
  vi U, V, A, B;
  rep(i,0,n) if(mi.used[i]) {
    U.emplace_back(u[i]);
    V.emplace_back(v[i]);
    pii p = from_col[cols[i]];
    A.emplace_back(p.first);
    B.emplace_back(p.second);
  }
  assert(sz(U) < sz(x));
  if(sz(U) < sz(x)-1) return 0;
  build(U, V, A, B);
  return 1;
}
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |