結果
問題 | No.880 Yet Another Segment Tree Problem |
ユーザー |
![]() |
提出日時 | 2024-09-04 15:51:45 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 8,366 bytes |
コンパイル時間 | 3,181 ms |
コンパイル使用メモリ | 256,980 KB |
実行使用メモリ | 25,164 KB |
最終ジャッジ日時 | 2024-09-04 15:52:08 |
合計ジャッジ時間 | 22,428 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 31 TLE * 1 -- * 5 |
ソースコード
// ちゃんと確認する!!// 抽象化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/021457namespace Segment_Tree_Beats_INVAl {// 型の指定using R = long long;R inf = 1e9 + 100;// deta・RSQ 用の型struct T {R sum;R left;R Max;R len;bool same;T(R x, R _size = 1): 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(a.left*b.left/gcd(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;if (a.set) b = T(a.set, b.len);if (a.togcd) {if (b.len == 1)b = T(gcd(b.Max, a.togcd));else if (b.left == inf or a.togcd % b.left)b.same = false;}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_INVAlusing 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/880using R = ll;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, Segment_Tree_Beats_INVAl::E::update(d) );}if (a == 2) {cin >> d;seg.apply(b, c, Segment_Tree_Beats_INVAl::E::GCD(d));}if (a == 3) {// cin >> d;cout << seg.prod(b, c).Max << endl;}if (a == 4) {// cin >> d;cout << seg.prod(b, c).sum << endl;}}}