Official

F - Falling Bars Editorial by en_translator


We assume that R1R2RNR_1 \geq R_2\geq \dots \geq R_N.

First of all, we can safely ignore bars j (j>i)j\ (j > i) when determining the final position of bar ii (because the bars that are initially above bar ii never end up below bar ii). Thus, we may consider the last position of bar ii for i=1,2,,Ni=1,2,\dots,N, one by one.

Let us consider how to find the final position of some bar a (1aN)a\ (1\leq a\leq N) when that of bars i (i<a)i\ (i < a) are already known.

For each 1jW1\leq j\leq W, let mjm_j be the row index of the topmost cell in column jj that is occupied by one of bars 1,2,,a11,2,\dots,a-1 after sufficient time (or H+1H+1 if none of the cells in the column is occupied).

Then, we can prove that the row RaR'_a at which bar aa will end up after sufficient time is min{mj:Caj<Ca+La}1\min\{m_j: C_a \leq j < C_a+L_a\}-1.

Once you have found the final row of bar aa, we need to appropriately update the values mjm_j to find the final positions of bars a+1,a+2,a+1,a+2,\dots. Specifically, we need to set mjm_j to RaR'_a for each j (Caj<Ca+La)j\ (C_a \leq j < C_a+L_a).

In summary, it is sufficient to do the following process fast:

  1. Initialize as m1=m2==mW=H+1m_1=m_2=\dots=m_W=H+1.
  2. For i=1,2,,Ni=1,2,\dots,N, do the following:
    1. Let Rimin{mj:Cij<Ci+Li}1R'_i\leftarrow \min\{m_j: C_i \leq j < C_i+L_i\}-1.
    2. For each j (Cij<Ci+Li)j\ (C_i \leq j < C_i+L_i), set mjRim_j\leftarrow R'_i.

This can be processed in a total of O(W+NlogW)O(W+N\log W) time using a lazy segment tree allowing segment-min & segment-update, or segment-min & segment-chmin (chmin = change to the smaller value). Therefore, the problem has been solved.

Sample code (C++9:

Copy
  1. #include <bits/stdc++.h>
  2. #include <atcoder/lazysegtree>
  3. using namespace std;
  4. using namespace atcoder;
  5. const int inf = 1e9;
  6. using S = int;
  7. using F = int;
  8. S op(S l, S r) { return min(l, r); }
  9. S e() { return inf; }
  10. S mapping(F l, S r) { return min(l, r); }
  11. F composition(F l, F r) { return min(l, r); }
  12. F id() { return inf; }
  13. int main() {
  14. int h, w, n;
  15. cin >> h >> w >> n;
  16. vector<int> r(n), c(n), l(n);
  17. for (int i = 0; i < n; i++) {
  18. cin >> r[i] >> c[i] >> l[i];
  19. --c[i];
  20. }
  21. vector<int> ord(n);
  22. iota(ord.begin(), ord.end(), 0);
  23. sort(ord.begin(), ord.end(), [&](int i, int j) { return r[i] > r[j]; });
  24. vector<int> ans(n);
  25. lazy_segtree<S, op, e, F, mapping, composition, id> seg(vector<int>(w, h + 1));
  26. for (int i: ord) {
  27. ans[i] = seg.prod(c[i], c[i] + l[i]) - 1;
  28. seg.apply(c[i], c[i] + l[i], ans[i]);
  29. }
  30. for (int i = 0; i < n; i++) {
  31. cout << ans[i] << '\n';
  32. }
  33. }
#include <bits/stdc++.h>
#include <atcoder/lazysegtree>

using namespace std;
using namespace atcoder;

const int inf = 1e9;

using S = int;
using F = int;

S op(S l, S r) { return min(l, r); }

S e() { return inf; }

S mapping(F l, S r) { return min(l, r); }

F composition(F l, F r) { return min(l, r); }

F id() { return inf; }

int main() {
    int h, w, n;
    cin >> h >> w >> n;
    vector<int> r(n), c(n), l(n);
    for (int i = 0; i < n; i++) {
        cin >> r[i] >> c[i] >> l[i];
        --c[i];
    }
    vector<int> ord(n);
    iota(ord.begin(), ord.end(), 0);
    sort(ord.begin(), ord.end(), [&](int i, int j) { return r[i] > r[j]; });

    vector<int> ans(n);
    lazy_segtree<S, op, e, F, mapping, composition, id> seg(vector<int>(w, h + 1));
    for (int i: ord) {
        ans[i] = seg.prod(c[i], c[i] + l[i]) - 1;
        seg.apply(c[i], c[i] + l[i], ans[i]);
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << '\n';
    }
}

posted:
last update:



2025-04-02 (Wed)
03:17:31 +00:00