답안 #956270

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
956270 2024-04-01T12:54:37 Z chrisvilches Dragon 2 (JOI17_dragon2) C++14
0 / 100
398 ms 1944 KB
#include <bits/stdc++.h>
using namespace std;
using ll = int;

ll Bx, By;

map<pair<int, int>, int> query_ans;

vector<vector<int>> upper_triangles;

// TODO: Idea super dificil de implementar: Crear un arbol de convex hulls en ord_b
//       Para poder acceder a informacion global (por ejemplo saber cuantos puntos hay
//       dentro del convex hull y si ese poligono cabe dentro de un triangulo, etc). No se
//       si sirva de algo.

struct Point {
  ll x, y;
  int idx;
  inline Point operator-(const Point& p) const { return {x - p.x, y - p.y, idx}; }
  inline Point operator+(const Point& p) const { return {x + p.x, y + p.y, idx}; }
  inline long long cross(const Point& p) const {
    return x * (long long)p.y - y * (long long)p.x;
  }
  inline bool operator<(const Point& p) const {
    return to_upper().cross(p.to_upper()) > 0;
  }
  inline Point to_upper() const { return above() ? *this : negate(); }
  inline bool above() const {
    // TODO: Improve this
    // const Point B{Bx, By, idx};
    return Bx * (long long)y - By * (long long)x > 0;
    // return B.cross(*this) > 0;
  }
  inline Point negate() const { return {-x, -y, idx}; }
};

short orientation(const Point& o, const Point& a, const Point& b) {
  // assert((a - o).cross(b - o) != 0);
  const long long x = (a - o).cross(b - o);
  return (x > 0) - (x < 0);
}

// short bit[30'001];
// int bit_n = 30'001;

// void clear(const int n) { memset(bit, 0, sizeof(short) * n); }

// // TODO: Return should be int, not short.
// int sum_single(int r) {
//   int ret = 0;
//   for (; r >= 0; r = (r & (r + 1)) - 1) ret += bit[r];
//   return ret;
// }

// int sum(int l, int r) { return sum_single(r) - sum_single(l - 1); }

// void add(int idx, const short delta) {
//   for (; idx < bit_n; idx = idx | (idx + 1)) bit[idx] += delta;
// }

vector<vector<Point>> order_by_b;

bool cmp_by_b(const Point& p, const Point& q) {
  const bool a1 = p.above();
  const bool a2 = q.above();
  if (a1 != a2) return a1;
  return p.cross(q) > 0;
}

int handle_query(const vector<Point>& points1, const vector<Point>& points2,
                 const vector<Point>& ord_b, const Point& B, const int attacked_idx) {
  if (points1.empty() || points2.empty()) return 0;

  // bit_n = (int)points2.size();
  // clear(points2.size());

  // const int n = points2.size();

  // int points_above = 0;
  // int points_below = 0;

  // for (const auto& q : points2) {
  //   if (!q.above()) {
  //     add(q.idx, 1);
  //     points_below++;
  //   } else {
  //     points_above++;
  //   }
  // }

  const auto mid = lower_bound(ord_b.begin(), ord_b.end(), (Point{0, 0} - B), cmp_by_b);

  int total = 0;

  // query_ans[{1, 1}] = 1;
  // auto& ref = query_ans.at({1, 1});

  int points_activated_above = 0;
  int points_deactivated_below = 0;

  int j = 0;
  for (const Point& p : points1) {
    while (j < (int)points2.size()) {
      const Point& q = points2[j];

      if (!(q < p)) break;
      // add(q.idx, q.above() ? 1 : -1);

      if (q.above()) points_activated_above++;
      if (!q.above()) points_deactivated_below++;

      j++;
    }

    Point from_point = p;
    Point to_point = B;
    to_point.x += B.x - p.x;
    to_point.y += B.y - p.y;

    if (p.above()) {
      auto it2 = lower_bound(mid, ord_b.end(), to_point - B, cmp_by_b);

      const int below_to_angle = it2 - mid;
      const int activated_below = below_to_angle - points_deactivated_below;
      total += activated_below;

      // for (auto it = mid; it != ord_b.end(); it--) {
      //   if (it == ord_b.end()) break;
      //   const Point q = *it + B;
      //   if (!q.above()) continue;
      //   // if (q.above()) {
      //   assert(q.above());
      //   total += q.cross(p) > 0 && orientation(B, p, q) > 0;
      //   // }
      //   if (it == ord_b.begin()) break;
      //   if (orientation(B, q, p) > 0) break;
      // }

      // TODO: Improve range of loop (make it smaller)
      for (auto it = ord_b.begin(); it != ord_b.end(); it++) {
        // assert(it->above());
        if (it->above()) total += it->cross(p) > 0 && orientation(B, p, *it) > 0;
      }

    } else {
      swap(from_point, to_point);
      const auto it2 = lower_bound(ord_b.begin(), mid, B - p, cmp_by_b);
      const int above_to_angle = it2 - ord_b.begin();
      const int activated_above = points_activated_above - above_to_angle;
      total += activated_above;

      for (const auto& q : points2) {
        if (!q.above()) {
          total += p.cross(q) > 0 && orientation(B, p, q) < 0;
        }
      }
    }
  }
  return total;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int N, M, Q;

  int t = 0;
  while (cin >> N >> M) {
    cerr << "--- " << t << endl;
    vector<vector<Point>> tribe_points(M + 1);
    order_by_b = vector<vector<Point>>(M + 1);
    for (int i = 0; i < N; i++) {
      Point p;
      int tribe;
      cin >> p.x >> p.y >> tribe;
      tribe_points[tribe].push_back(p);
    }

    Point A;
    cin >> A.x >> A.y;
    cin >> Bx >> By;
    cin >> Q;

    Bx -= A.x;
    By -= A.y;

    for (auto& points : tribe_points) {
      for (auto& p : points) p = p - A;
    }

    const Point B{Bx, By, -1};

    for (int m = 0; m <= M; m++) {
      auto& points = tribe_points[m];

      for (auto& p : tribe_points.at(m)) p = p - B;
      sort(points.begin(), points.end(), cmp_by_b);
      for (int i = 0; i < (int)points.size(); i++) {
        points[i].idx = i;
      }
      order_by_b[m] = tribe_points.at(m);
      for (auto& p : tribe_points.at(m)) p = p + B;
    }

    for (auto& points : tribe_points) {
      sort(points.begin(), points.end());
    }

    const Point origin{0, 0, -1};

    // upper_triangles.assign(M + 1, vector<int>());

    // for (int m = 0; m <= M; m++) {
    //   clear(30'000);
    //   const auto& ord_b = order_by_b[m];
    //   for (const auto& p : tribe_points[m]) {
    //     if (!p.above()) {
    //       upper_triangles[m].emplace_back(0);
    //       continue;
    //     }

    //     add(p.idx, 1);
    //     upper_triangles[m].emplace_back(sum(p.idx, 30'000));
    //   }
    //   assert(ord_b.size() == upper_triangles[m].size());
    // }

    // TODO: Are the fenwick queries actually faster???? DO some experiments

    // TODO: Set this value more properly, and explain that this doesn't really help
    //       but it's something. (assuming fenwick is ACTUALLY faster)

    // TODO: Comment that this solution is probably not the intended one. The example
    // solution is much faster (under a second).
    // TODO: The thing is, I don't want to leave this code without the radial sweep, I
    // want to add it for the lulz.

    clock_t begin = clock();

    while (Q--) {
      int i, j;
      cin >> i >> j;
      // cerr << tribe_points[i].size() * tribe_points[j].size() << endl;
      // const long long size = tribe_points[i].size() * tribe_points[j].size();

      const int ans =
          handle_query(tribe_points.at(i), tribe_points.at(j), order_by_b.at(j), B, j);
      cout << ans << '\n';
    }
    clock_t end = clock();
    double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
    cerr << fixed << setprecision(3) << "   time: " << elapsed_secs << endl;

    t++;
  }
}

Compilation message

dragon2.cpp: In function 'int main()':
dragon2.cpp:209:17: warning: unused variable 'origin' [-Wunused-variable]
  209 |     const Point origin{0, 0, -1};
      |                 ^~~~~~
# 결과 실행 시간 메모리 Grader output
1 Incorrect 5 ms 600 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 398 ms 1944 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 5 ms 600 KB Output isn't correct
2 Halted 0 ms 0 KB -