結果
問題 | No.880 Yet Another Segment Tree Problem |
ユーザー | 7deQSJCy8c4Hg7I |
提出日時 | 2024-09-04 14:56:05 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 8,533 bytes |
コンパイル時間 | 3,262 ms |
コンパイル使用メモリ | 256,340 KB |
実行使用メモリ | 25,128 KB |
最終ジャッジ日時 | 2024-09-04 14:56:28 |
合計ジャッジ時間 | 22,288 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
25,128 KB |
testcase_01 | AC | 3 ms
6,944 KB |
testcase_02 | AC | 4 ms
6,944 KB |
testcase_03 | AC | 4 ms
6,940 KB |
testcase_04 | AC | 4 ms
6,940 KB |
testcase_05 | AC | 3 ms
6,940 KB |
testcase_06 | AC | 3 ms
6,940 KB |
testcase_07 | AC | 4 ms
6,940 KB |
testcase_08 | AC | 4 ms
6,944 KB |
testcase_09 | AC | 5 ms
6,940 KB |
testcase_10 | AC | 4 ms
6,940 KB |
testcase_11 | AC | 588 ms
18,132 KB |
testcase_12 | AC | 611 ms
18,172 KB |
testcase_13 | AC | 404 ms
18,168 KB |
testcase_14 | AC | 591 ms
18,256 KB |
testcase_15 | AC | 589 ms
18,144 KB |
testcase_16 | AC | 645 ms
18,332 KB |
testcase_17 | AC | 518 ms
18,196 KB |
testcase_18 | AC | 519 ms
18,304 KB |
testcase_19 | AC | 437 ms
18,320 KB |
testcase_20 | AC | 449 ms
18,192 KB |
testcase_21 | AC | 475 ms
18,308 KB |
testcase_22 | AC | 440 ms
18,288 KB |
testcase_23 | AC | 455 ms
18,244 KB |
testcase_24 | AC | 431 ms
18,296 KB |
testcase_25 | AC | 409 ms
18,400 KB |
testcase_26 | AC | 446 ms
18,292 KB |
testcase_27 | AC | 405 ms
18,388 KB |
testcase_28 | AC | 424 ms
18,332 KB |
testcase_29 | AC | 576 ms
18,140 KB |
testcase_30 | AC | 584 ms
18,328 KB |
testcase_31 | AC | 651 ms
18,372 KB |
testcase_32 | TLE | - |
testcase_33 | -- | - |
testcase_34 | -- | - |
testcase_35 | -- | - |
testcase_36 | -- | - |
testcase_37 | -- | - |
ソースコード
// ちゃんと確認する!! // 抽象化segtree beats #include <bits/stdc++.h> using namespace std; #define rep(i, n) for (ll i = (0); i < (ll)(n); i++) // 参考: https://smijake3.hatenablog.com/entry/2019/04/28/021457 namespace Segment_Tree_Beats_INVAl { // 型の指定 using R = long long; R inf = 1e9; // deta・RSQ 用の型 struct T { R sum; R left; R Max; R len; bool same; T(R x) : sum(x), left(x), Max(x), len(1), same(true) {} T(R x, R _size) : sum(x * _size), left(x), Max(x), len(_size), same(true) {} T() : sum(0), left(1), Max(0), len(0), same(true) {} }; // モノイドの結合律(足し算とか掛け算とか) T op(T a, T b) { if (a.len == 0) return b; if (b.len == 0) return a; T ret; ret.sum = a.sum + b.sum; ret.left = min(lcm(a.left, b.left), inf); ret.Max = max(a.Max, b.Max); ret.len = a.len + b.len; return ret; } // モノイドの単位元 T e() { return T(); } // 任意の遅延伝搬用の型 struct E { R togcd; R set; E() : togcd(0), set(0) {} E(R g, R up) : togcd(g), set(up) {} static E GCD(R g) { return E(g, 0); } static E update(R g) { return E(0, g); } }; // dataに対する遅延伝搬(今回は除算を行うので長さは必要) // 要素単体の更新は長さ1の区間の更新ととらえればいい。 T mapping(E a, T b) { // 正確に処理できないものが確実な時は飛ばしていい if (!b.same) return b; // set if (a.set) b = T(a.set, b.len); if (a.togcd) { if (b.len == 1) b = T(gcd(b.Max, a.togcd), b.len); else if (b.left == inf || a.togcd % b.left) b.same = false; // その他の場合は変更する範囲内の最小公倍数が変更する最大公約数になるので、値が変更されないので終了で構わない else b.same = true; } return b; } // fnewが後の操作 E composition(E fnew, E fold) { // setとgcd処理は両方とも同時に持たないようにしておく(片方は確実に0) ; // 後の方に更新処理が存在する場合、前の方の処理を棄却する if (fnew.set) { return E::update(fnew.set); } // 後の方に更新処理が存在せず、前の方に更新処理を行う場合、前の更新操作を行ってから後の方の操作でgcd操作を行うので実質gcdの値を更新処理する動作と同じになる。 else if (fold.set) { return E::update(gcd(fnew.togcd, fold.set)); } else // 前も後ろも更新処理がない場合はgcd処理のみを考えればいい、前のgcdと後のgcd二回の操作を一回にまとめる return E::GCD(gcd(fnew.togcd, fold.togcd)); } E id() { return E(); } struct Segment_Tree_Beats { private: int n{}, sz{}, height{}; vector<T> data; // 任意の遅延伝搬(単位元はid()) vector<E> lazy; void update(int k) { data[k] = op(data[2 * k], data[2 * k + 1]); } void push(int k) { apply_push(k); } void apply_push(int k) { all_apply(2 * k, lazy[k]); all_apply(2 * k + 1, lazy[k]); lazy[k] = id(); } void push_apply(int k, E x) { data[k] = mapping(x, data[k]); lazy[k] = composition(x, lazy[k]); } // 抽象遅延伝搬作業 void all_apply(int k, E x) { push_apply(k, x); if (!data[k].same) { push(k); update(k); } } public: Segment_Tree_Beats() = default; explicit Segment_Tree_Beats(int n) : Segment_Tree_Beats(vector<R>(n, 0)) {} explicit Segment_Tree_Beats(const vector<R> &v) : n(v.size()) { sz = 1; height = 0; while (sz < n) sz <<= 1, height++; data = vector<T>(2 * sz, e()); lazy = vector<E>(2 * sz, id()); build(v); } void build(const vector<R> &v) { assert(n == (int)v.size()); for (int k = 0; k < n; k++) { data[k + sz] = T(v[k]); } for (int k = sz - 1; k > 0; k--) update(k); } void set(int k, const T x) { assert(0 <= k && k < n); k += sz; for (int i = height; i > 0; i--) push(k >> i); data[k] = x; for (int i = 1; i <= height; i++) update(k >> i); } T get(int k) { assert(0 <= k && k < n); k += sz; for (int i = height; i > 0; i--) push(k >> i); return data[k]; } T operator[](int k) { return get(k); } // i=l,...r-1においてmapping(x,v[i]) void apply(int l, int r, E x) { if (l >= r) return; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } // 値を更新する区間のdataとlazyの値を更新 int l2 = l, r2 = r; for (; l < r; l >>= 1, r >>= 1) { if (l & 1) all_apply(l++, x); if (r & 1) all_apply(--r, x); } l = l2, r = r2; // 更新する区間を部分的に含んだ区間においてボトムアップで子ノードに伝搬させながらdataの値を更新 for (int i = 1; i <= height; i++) { if (((l >> i) << i) != l) update(l >> i); if (((r >> i) << i) != r) update((r - 1) >> i); } } // op(A[l],A[l+1],...,A[r-1])を求める T prod(int l, int r) { assert(0 <= l && l <= r && r <= n); if (l >= r) return e(); l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } T L = e(), R = e(); // 値をチェックする区間のdataの値をチェック for (; l < r; l >>= 1, r >>= 1) { if (l & 1) L = op(L, data[l++]); if (r & 1) R = op(data[--r], R); } return op(L, R); } T all_prod() const { return data[1]; } // lに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す template <typename C> int max_right(int l, const C check) { if (l >= n) return n; l += sz; for (int i = height; i > 0; i--) push(l >> i); T sum = e(); do { while ((l & 1) == 0) l >>= 1; if (check(op(sum, data[l]))) { while (l < sz) { push(l); l <<= 1; auto nxt = op(sum, data[l]); if (not check(nxt)) { sum = nxt; l++; } } return l + 1 - sz; } sum = op(sum, data[l++]); } while ((l & -l) != l); return n; } // rに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す template <typename C> int min_left(int r, const C &check) { if (r <= 0) return 0; r += sz; for (int i = height; i > 0; i--) push((r - 1) >> i); T sum = e(); do { r--; while (r > 1 and (r & 1)) r >>= 1; if (check(op(data[r], sum))) { while (r < sz) { push(r); r = (r << 1) + 1; auto nxt = op(data[r], sum); if (not check(nxt)) { sum = nxt; r--; } } return r - sz; } sum = op(data[r], sum); } while ((r & -r) != r); return 0; } }; } // namespace Segment_Tree_Beats_INVAl using Segment_Tree_Beats_INVAl::Segment_Tree_Beats; // set(k,x) A[k]=xに更新 // get(k,x) A[k]を返す // prod(l,r) : op(A[l],A[l+1],...,A[r-1])を求める // apply(l,r,x) : i=l,...r-1においてmapping(x,A[i])を実行 // max_right(l,C) : // lに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す // min_left(r, C) : // rに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す // Sはdataを表している。 using ll = long long; using vll = vector<ll>; // https : // yukicoder.me/problems/no/880 int main() { cin.tie(0)->sync_with_stdio(0); cout << fixed << setprecision(20); ll a = 0, b = 0; ll a2, b2, c2; ll a1 = 0, b1 = 0; ll c = 0, c1; ll p = 1; ll N, M; ll t; ll K; ll h, w; ll L; string S, T; cin >> N >> t; vll A(N); for (int i = 0; i < N; i++) cin >> A[i]; // cout << A.size() << endl; Segment_Tree_Beats seg(A); rep(_, t) { ll d; cin >> a >> b >> c; --b; if (a == 1) { cin >> d; seg.apply(b, c, {0, d}); } if (a == 2) { cin >> d; seg.apply(b, c, {d, 0}); } if (a == 3) { // cin >> d; cout << seg.prod(b, c).Max << endl; } if (a == 4) { // cin >> d; cout << seg.prod(b, c).sum << endl; } } }