Submission #1263333

#TimeUsernameProblemLanguageResultExecution timeMemory
1263333rtriPark (BOI16_park)C++20
0 / 100
2595 ms2188 KiB
#include <bits/stdc++.h>
#include <deque>
using namespace std;

int n, m, w, h;
vector<tuple<int, int, int>> trees;

bool line_of_sight(double x1, double y1, double x2, double y2, int radius) {
  for (auto [x, y, base_r] : trees) {
    int r = base_r + radius;
    double u = (double)((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) /
               (double)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    double ex = x1 + clamp(u, 0., 1.) * (x2 - x1);
    double ey = y1 + clamp(u, 0., 1.) * (y2 - y1);
    double dist = sqrt((ex - x) * (ex - x) + (ey - y) * (ey - y));
    if (dist < r)
      return false;
  }
  return true;
}

pair<double, double> get_exit(int exit_id, int radius) {
  if (exit_id == 1)
    return {radius, radius};
  else if (exit_id == 2)
    return {w - radius, radius};
  else if (exit_id == 3)
    return {w - radius, h - radius};
  else if (exit_id == 4)
    return {radius, h - radius};
  else
    exit(-1);
}

bool pathfind(int start, int end, int radius) {
  auto [startx, starty] = get_exit(start, radius);
  auto [endx, endy] = get_exit(end, radius);

  deque<tuple<double, double, int>> que;
  que.push_back({startx, starty, 0});
  while (!que.empty()) {
    auto [x, y, r] = que.front();
    que.pop_front();

    cerr << x << " " << y << " " << que.size() << endl;
    if (line_of_sight(x, y, endx, endy, radius))
      return true;

    for (auto [treex, treey, base_r] : trees) {
      int treer = base_r + radius;

      double d = sqrt(pow(x - treex, 2) + pow(y - treey, 2));
      double alpha = atan2(y - treey, x - treex);
      double alpha_inv = atan2(treey - y, treex - x);

      vector<tuple<double, double, double, double>> cand = {};

      if (d >= r + treer) {
        double int_theta = acos((r + treer) / d);
        cand.push_back({cos(int_theta + alpha_inv), sin(int_theta + alpha_inv),
                        cos(int_theta - alpha), sin(int_theta - alpha)});
        cand.push_back({cos(int_theta - alpha_inv), sin(int_theta - alpha_inv),
                        cos(int_theta + alpha), sin(int_theta + alpha)});

        double ext_theta = acos(abs(r - treer) / d);
        cand.push_back({cos(ext_theta + alpha_inv), sin(ext_theta + alpha_inv),
                        cos(ext_theta - (M_PI + alpha)),
                        sin(ext_theta - (M_PI + alpha))});
        cand.push_back({cos(ext_theta - alpha_inv), sin(ext_theta - alpha_inv),
                        cos(ext_theta - (M_PI - alpha)),
                        sin(ext_theta - (M_PI - alpha))});
      }

      for (auto [cx, cy, nx, ny] : cand) {
        // TODO requires checking if sphere intersects or we are allowed to
        // slide
        // cx = cx * r + x, cy = cy * r + y;
        nx = nx * treer + treex, ny = ny * treer + treey;

        if (line_of_sight(x, y, nx, ny, radius))
          que.push_back({nx, ny, treer});
      }
    }
  }

  return false;
}

int main() {
  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);

  cin >> n >> m >> w >> h;

  for (int i = 0; i < n; i++) {
    int x, y, r;
    cin >> x >> y >> r;
    trees.push_back({x, y, r});
  }

  vector<pair<int, int>> queries;

  for (int i = 0; i < m; i++) {
    int r, e;
    cin >> r >> e;
    queries.push_back({e, r});
  }

  // Insikt 1: det finns bara 6 möjliga vägar (4 välj 2)
  // Insikt 2: vi kan binärsöka över varje vägbredd (ca. log 1e9 \approx 30)

  vector<vector<int>> max_width(5, vector<int>(5, -1));

  for (int start = 1; start <= 4; start++)
    for (int end = start; end <= 4; end++) {
      if (start == end) {
        max_width[start][end] = 1e9;
        max_width[end][start] = 1e9;
        continue;
      }

      int l = 0, r = min(w, h) / 4 + 3;
      while (l + 1 < r) {
        int mid = (l + r) / 2;
        if (pathfind(start, end, mid))
          l = mid;
        else
          r = mid;
      }
      max_width[start][end] = l;
      max_width[end][start] = r;
    }

  for (auto [e, r] : queries) {
    for (int exit = 1; exit <= 4; exit++)
      if (r <= max_width[e][exit])
        cout << exit;
    cout << "\n";
  }

  return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...