[ABC368] G - Add and Multiply Queries

[Q] G - Add and Multiply Queries
日立ヴァンタラプログラミングコンテスト2024。

Fで大量にWAを出して落ち込んでいる最中、EかGのどちらに進むか悩む。Eに行ってしまう。
Gがカスタマイズを要するセグ木に見えてひよったからだ。そうして大敗を喫する。
実際はBITとsetで事足りるのに。。

考察
1. クエリの回答が1e18までしか来ない。
2. つまり、配列Bに1,1,1,1,1…という箇所がたくさんあるはず。その箇所のAを累積和をとっておけばよさそう。BITで事足りる
3. 配列Bの中で値が2以上のindexを取得できれば嬉しい。セグ木でもいいけど、setでいい。
横着してlower_boundはダメ。sort済み配列にしか使用できない関数だ。当たり前のことなのになんか忘れてしまっていた。
sort済みでない配列にlower_bound(upper_bound)をすると何が得られる?

細かい2点。
4. v = 0から始まるので、最初はA[L]を必ずとればいい。
5. Bの値が2以上のindex_iは、v = max(v + A[i], v * B[i]) で大きいほうをとればいい。
これを実装する。

実装

template<ll BT>
struct Bit
{
  ll dat[BT+10]{};
  void add(ll i, ll x){
    ++i;
    for(; i<BT; i += i&-i) dat[i] += x;
  }
  // iの値を取り出したいときはsum(i)
  ll sum(ll i){ // [0, i]
    if (i<0) return 0;
    if (i>=BT-1) i = BT-2;
    ++i;
    ll res = 0;
    for(; i>0; i -= i&-i) res += dat[i];
    return res;
  }
  ll rangesum(ll L, ll R){ // [L, R)
    return sum(R - 1) - sum(L - 1);
  }
};

int main(){
  cincout();

  ll N;
  cin >> N;
  Bit<100010> bit;
  vector<ll> A(N), B(N);
  set<ll> S;
  rep(i, N){
    cin >> A[i];
    bit.add(i, A[i]);
  }
  rep(i, N){
    cin >> B[i];
    if (B[i] > 1) S.insert(i); // Bが2以上の時掛け算を採用する候補になる。Aが1e9のときはAをとるかもね
  }
  S.insert(N); // 番兵node

  ll Q;
  cin >> Q;
  while(Q--){
    ll type;
    cin >> type;
    if (type == 1){
      ll i, x;
      cin >> i >> x;
      --i;
      bit.add(i, x - A[i]);
      A[i] = x;
    }
    else if (type == 2){
      ll i, x;
      cin >> i >> x;
      --i;
      if (B[i] > 1 && x == 1) S.erase(i);
      B[i] = x;
      if (B[i] > 1) S.insert(i);
    }
    else{
      ll l, r;
      cin >> l >> r;
      --l;
      ll v = 0;
      for(ll i = l; i < r; ++i){
        if (v < 1){
          v += A[i];
        }
        else{
          ll ni = *S.lower_bound(i);
          if (ni < r){
            if (ni > i){ // Bが1,1,...の箇所のAの累積和
              v += bit.rangesum(i, ni);
            }
            v = max(v + A[ni], v * B[ni]); // AかBの大きいほうを採用
            i = ni;
          }
          else{
            v += bit.rangesum(i, r);
            break;
          }
        }
      }
      cout << v << endl;
    }
  }
}

https://atcoder.jp/contests/abc368/submissions/57112403

いいなと思ったら応援しよう!