H - Somen Nagashi Editorial
by
sounansya
セグメント木を用いる解法
セグメント木を用いる解法を紹介します。
\(\text{seg}[k]\) を人 \(k\) が戻ってくる時刻 (ただしこの値が現在時刻以下であれば既に列に並んでいるとする) とします。ただし、はじめ全ての人が列に並んでいるので初期値は \(\text{seg}[k]=0\) とします。この \(\text{seg}[k]\) を元に各出来事を処理していくことを考えます。
各出来事でそうめんを得る人の番号は \(\text{seg}[k] \le T_i\) を満たす最小の \(k\) です。これはセグメント木上の二分探索を行うことで \(O(\log N)\) で求めることができます。 人 \(k\) が一旦列から離れることは \(\text{seg}[k]\) を \(T_i+S_i\) に更新することで表現できます。この操作も \(O(\log N)\) で行うことができます。
以上でこの問題を解くことができます。計算量は \(O(N+M\log N)\) です。
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
int op(int a, int b) { return min(a, b); }
int inf() { return 1 << 30; }
int jud;
bool f(int x) { return x > jud; }
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
atcoder::segtree<int, op, inf> seg(a);
vector<long long> ans(n);
for(int i = 0; i < m; i++) {
int t, w, s;
cin >> t >> w >> s;
jud = t;
int idx = seg.max_right(0, f);
if (idx == n) continue;
ans[idx] += w;
seg.set(idx, t + s);
}
for (long long i : ans) cout << i << '\n';
return 0;
}
posted:
last update: