제출 #1369711

#제출 시각아이디문제언어결과실행 시간메모리
1369711avighna분수 공원 (IOI21_parks)C++20
5 / 100
857 ms138712 KiB
#include <bits/stdc++.h>

using namespace std;

void build(vector<int> u, vector<int> v, vector<int> a, vector<int> b);

namespace {
class dsu {
  int n;
  vector<int> par;

public:
  dsu(int n) : n(n), par(n) {
    iota(par.begin(), par.end(), 0);
  }

  int root(int u) { return u == par[u] ? u : par[u] = root(par[u]); }

  void merge(int u, int v) {
    u = root(u), v = root(v);
    if (u != v) {
      par[v] = u;
    }
  }
};

class twosat {
  int n;
  vector<vector<int>> adj;

  int id(int a, int nega) { return a + n * nega; }

public:
  twosat(int n) : n(n), adj(2 * n) {}

  void add_implication(int nega, int a, int negb, int b) {
    adj[id(a, nega)].push_back(id(b, negb));
    adj[id(b, !negb)].push_back(id(a, !nega));
  }

  vector<int> solve() {
    vector<vector<int>> adjt(2 * n);
    for (int i = 0; i < 2 * n; ++i) {
      for (int &j : adj[i]) {
        adjt[j].push_back(i);
      }
    }

    vector<bool> vis(2 * n);
    vector<int> stk;
    auto dfs = [&](auto &&self, int u) {
      if (vis[u]) {
        return;
      }
      vis[u] = true;
      for (int &i : adj[u]) {
        self(self, i);
      }
      stk.push_back(u);
    };
    swap(adj, adjt);
    for (int i = 0; i < 2 * n; ++i) {
      dfs(dfs, i);
    }
    swap(adj, adjt);
    auto post = stk;
    reverse(post.begin(), post.end());

    vis.assign(2 * n, false);
    vector<int> root(2 * n);
    vector<vector<int>> with_root(2 * n);
    for (int &u : post) {
      if (vis[u]) {
        continue;
      }
      stk.clear();
      dfs(dfs, u);
      for (int &i : stk) {
        root[i] = stk[0], with_root[stk[0]].push_back(i);
      }
    }

    for (int i = 0; i < n; ++i) {
      if (root[i] == root[i + n]) {
        return {};
      }
    }

    vis.assign(2 * n, false);
    vector<int> topo(2 * n);
    int idx = 0;
    auto dfs2 = [&](auto &&self, int u) {
      u = root[u];
      if (vis[u]) {
        return;
      }
      vis[u] = true;
      for (int &uu : with_root[u]) {
        for (int &i : adj[uu]) {
          self(self, i);
        }
      }
      topo[u] = idx++;
    };
    for (int i = 0; i < 2 * n; ++i) {
      dfs2(dfs2, i);
    }

    vector<int> ans(n);
    for (int i = 0; i < n; ++i) {
      ans[i] = topo[root[i]] < topo[root[i + n]];
    }
    return ans;
  }
};
} // namespace

int construct_roads(vector<int> x, vector<int> y) {
  const int n = x.size();
  vector<pair<pair<int, int>, int>> buf;
  for (int i = 0; i < n; ++i) {
    buf.push_back({{x[i], y[i]}, i});
  }
  sort(buf.begin(), buf.end());
  auto contains = [&](int x, int y) {
    pair<pair<int, int>, int> p = {{x, y}, -1};
    auto it = lower_bound(buf.begin(), buf.end(), p);
    return it != buf.end() && it->first == p.first;
  };
  auto compr = [&](int x, int y) {
    pair<pair<int, int>, int> p = {{x, y}, -1};
    return lower_bound(buf.begin(), buf.end(), p)->second;
  };

  vector<pair<int, int>> edges;
  for (int i = 0; i < n; ++i) {
    if (contains(x[i], y[i] + 2)) {
      edges.push_back({i, compr(x[i], y[i] + 2)});
    }
    if (contains(x[i], y[i] - 2)) {
      edges.push_back({i, compr(x[i], y[i] - 2)});
    }
    if (contains(x[i] + 2, y[i])) {
      edges.push_back({i, compr(x[i] + 2, y[i])});
    }
    if (contains(x[i] - 2, y[i])) {
      edges.push_back({i, compr(x[i] - 2, y[i])});
    }
  }

  vector<int> uu, vv, a, b;
  dsu dsu(n);
  auto vert = [&](pair<int, int> a) {
    return x[a.first] == x[a.second];
  };
  vector<pair<int, int>> bridges, benches;
  for (auto &[u, v] : edges) {
    if (dsu.root(u) == dsu.root(v)) {
      continue;
    }
    if (x[u] > x[v]) {
      swap(u, v);
    }
    if (y[u] > y[v]) {
      swap(u, v);
    }
    dsu.merge(u, v);
    bridges.push_back({u, v});
    uu.push_back(u), vv.push_back(v);
    if (vert({u, v})) {
      int my = (y[u] + y[v]) / 2;
      benches.push_back({x[u] - 1, my});
      benches.push_back({x[u] + 1, my});
    } else {
      int mx = (x[u] + x[v]) / 2;
      benches.push_back({mx, y[u] - 1});
      benches.push_back({mx, y[u] + 1});
    }
  }

  int num = 0;
  for (int i = 0; i < n; ++i) {
    num += dsu.root(i) == dsu.root(0);
  }
  if (num != n) {
    return 0;
  }

  sort(bridges.begin(), bridges.end());
  sort(benches.begin(), benches.end());
  bridges.erase(unique(bridges.begin(), bridges.end()), bridges.end());
  benches.erase(unique(benches.begin(), benches.end()), benches.end());
  auto bridge_exists = [&](pair<int, int> p) { return binary_search(bridges.begin(), bridges.end(), p); };
  auto bridge_idx = [&](pair<int, int> p) { return int(lower_bound(bridges.begin(), bridges.end(), p) - bridges.begin()); };
  auto bench_idx = [&](pair<int, int> p) { return int(lower_bound(benches.begin(), benches.end(), p) - benches.begin()); };

  vector<pair<int, int>> bridge_bench;
  for (int i = 0; i < int(uu.size()); ++i) {
    int u = uu[i], v = vv[i];
    if (vert({u, v})) {
      int my = (y[u] + y[v]) / 2;
      bridge_bench.push_back({bridge_idx({u, v}), bench_idx({x[u] - 1, my})});
      bridge_bench.push_back({bridge_idx({u, v}), bench_idx({x[u] + 1, my})});
    } else {
      int mx = (x[u] + x[v]) / 2;
      bridge_bench.push_back({bridge_idx({u, v}), bench_idx({mx, y[u] - 1})});
      bridge_bench.push_back({bridge_idx({u, v}), bench_idx({mx, y[u] + 1})});
    }
  }

  sort(bridge_bench.begin(), bridge_bench.end());
  bridge_bench.erase(unique(bridge_bench.begin(), bridge_bench.end()), bridge_bench.end());
  auto idx = [&](pair<int, int> p) { return int(lower_bound(bridge_bench.begin(), bridge_bench.end(), p) - bridge_bench.begin()); };

  twosat sat(bridge_bench.size());
  for (int i = 0; i < int(uu.size()); ++i) {
    int u = uu[i], v = vv[i];
    if (vert({u, v})) {
      sat.add_implication(1, idx({bridge_idx({u, v}), bench_idx({x[u] - 1, y[u]})}), 0, idx({bridge_idx({u, v}), bench_idx({x[u] + 1, y[u]})}));
      sat.add_implication(0, idx({bridge_idx({u, v}), bench_idx({x[u] - 1, y[u]})}), 1, idx({bridge_idx({u, v}), bench_idx({x[u] + 1, y[u]})}));
    } else {
      sat.add_implication(1, idx({bridge_idx({u, v}), bench_idx({x[u], y[u] - 1})}), 0, idx({bridge_idx({u, v}), bench_idx({x[u], y[u] + 1})}));
      sat.add_implication(0, idx({bridge_idx({u, v}), bench_idx({x[u], y[u] - 1})}), 1, idx({bridge_idx({u, v}), bench_idx({x[u], y[u] + 1})}));
    }
  }
  auto add_if_bridge = [&](int x1, int y1, int x2, int y2, vector<pair<int, int>> &avoid) {
    if (!contains(x1, y1) || !contains(x2, y2)) {
      return;
    }
    int u = compr(x1, y1);
    int v = compr(x2, y2);
    if (u > v) {
      swap(u, v);
    }
    if (bridge_exists({u, v})) {
      avoid.push_back({u, v});
    }
  };
  for (auto &[x, y] : benches) {
    vector<pair<int, int>> avoid;
    add_if_bridge(x - 1, y - 1, x - 1, y + 1, avoid);
    add_if_bridge(x + 1, y - 1, x + 1, y + 1, avoid);
    add_if_bridge(x - 1, y + 1, x + 1, y + 1, avoid);
    add_if_bridge(x - 1, y - 1, x + 1, y - 1, avoid);
    for (int i = 0; i < int(avoid.size()); ++i) {
      for (int j = 0; j < i; ++j) {
        sat.add_implication(0, idx({bridge_idx(avoid[i]), bench_idx({x, y})}), 1, idx({bridge_idx(avoid[j]), bench_idx({x, y})}));
      }
    }
  }

  auto ans = sat.solve();
  vector<int> uans, vans, aans, bans;
  for (int i = 0; i < int(ans.size()); ++i) {
    if (!ans[i]) {
      continue;
    }
    auto [bridx, benidx] = bridge_bench[i];
    auto [u, v] = bridges[bridx];
    auto [x, y] = benches[benidx];
    uans.push_back(u), vans.push_back(v), aans.push_back(x), bans.push_back(y);
  }
  build(uans, vans, aans, bans);
  return 1;
}

#ifdef MACOS_LOCAL
#include "grader.cpp"
#endif
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…