BOJ 1273 - 샷

image.png

$M$개의 쏘는 횟수에 대해, 쐈을 때의 높이가 아닌 쏜 row가 원래 어디 높이였는지를 구하면 쉽게 풀린다.

이는 세그먼트 트리로 이분탐색을 때려서 $O(N \log^2 N)$에 구해도 되고, 세그먼트 트리에서 K 번째 수를 찾는 테크닉을 써서 $O(N \log N)$에 구할 수도 있다.

여하튼 이걸 구하고나면, 각 블록마다 구간이 세 개 이하씩 나오는 부분들에 대해서 1, 2, 5 점을 구간합 배열이든 lazy propagation 세그먼트 트리든 표시해둔다음에 $M$개의 쏘는 시도에 대해서 합을 구해주면 된다.

template<class T>
struct fenwick {
   int n;
   vector<T> tree;
   fenwick(int n) : n(n) { tree.resize(n + 1); }
   T sum(int i) {
      T ret = 0;
      for (; i; i -= i & -i) ret += tree[i];
      return ret;
   }
   void update(int i, T x) { for (i++; i <= n; i += i & -i) tree[i] += x; }
   T query(int l, int r) { return l > r ? 0 : sum(r + 1) - sum(l); }
};
template<class T>
struct fenwick_point {
   fenwick<T> f;
   fenwick_point(int n) : f(fenwick<T>(n + 1)) {}
   void update(int l, int r, T x) { f.update(l, x), f.update(r + 1, -x); }
   T query(int i) { return f.query(0, i); }
};
template<class T>
struct fenwick_range {
   fenwick<T> d, c;
   fenwick_range(int n) : d(fenwick<T>(n + 1)), c(fenwick<T>(n + 1)) {}
   void update(int l, int r, T x) {
      d.update(l, x), d.update(r + 1, -x), c.update(l, (1 - l) * x), c.update(r + 1, r * x);
   }
   T query(int l, int r) {
      l--;
      return d.query(0, r) * r + c.query(0, r) - (l >= 0 ? d.query(0, l) * l + c.query(0, l) : 0);
   }
};
// endregion
const int MAX = 3e6;
void solve() {
   int n, m;
   cin >> n;
   vector<array<int, 3>> a(n);
   for (int i = 0; i < n; i++) cin >> a[i][0];
   for (int i = 0; i < n; i++) cin >> a[i][1];
   for (int i = 0; i < n; i++) cin >> a[i][2];
   cin >> m;
   vi shot(m);
   fv(shot);

   fenwick<int> fenw(MAX + 1);
   for (int i = 0; i < m; i++) {
      // 비어있는 만큼 위로 올려야함 O(Nlog^2N)
      int l = 1, r = MAX, f = -1;
      while (l <= r) {
         int m = l + (r - l) / 2;
         if (m - fenw.query(0, m) >= shot[i]) r = m - 1, f = m;
         else l = m + 1;
      }
      shot[i] = f;
      fenw.update(shot[i], 1);
   }

   fenwick_range<int> fenw_range(MAX + 1);
   for (int i = 0; i < n; i++) {
      if (a[i][0]) {
         fenw_range.update(0, a[i][0] - 1, 1);
      }
      if (a[i][1]) {
         fenw_range.update(a[i][0], a[i][0] + a[i][1] - 1, 2);
      }
      if (a[i][2]) {
         fenw_range.update(a[i][0] + a[i][1], a[i][0] + a[i][1] + a[i][2] - 1, 5);
      }
   }

   for (int i = 0; i < m; i++) {
      shot[i]--;
      cout << fenw_range.query(shot[i], shot[i]) << endl;
   }
}

Tags:

Categories:

Updated:

Comments