公式

E - 本棚の整理 / Organizing the Bookshelf 解説 by physics0523 印刷ページ


ACL にも実装がある Lazy Segtree を利用してこの問題に正解できます。

これは遅延伝搬セグメント木と呼ばれるもので、解説は例えば こちらの記事 を参照してください。

以降、 ACL の lazy_segtree のサンプルの形で説明します。
今回は、区間加算・区間和取得が実現できればよいです。

区間加算に対応するためには、 S として {区間内の総和, 区間の長さ} を保持するとうまくいきます。
これは、区間内の全ての要素に \(x\) 加算して区間内の総和を保持するという操作を行うために後者の情報が必要だからです。
より詳しい設計は実装例を参照してください。

Lazy Segtree の典型的な利用法として、こちらの記事 も参照ください。

実装例 (C++):

#include<bits/stdc++.h>
#include<atcoder/all>

using namespace std;
using namespace atcoder;
using ll=long long;

struct S{
  ll val;
  ll sz;
};

using F=ll;

S op(S l,S r){return {l.val+r.val,l.sz+r.sz};}
S e(){return {0,0};}
S mapping(F l, S r){
  return {r.val+l*r.sz,r.sz};
}
F composition(F l,F r){return (l+r);}
F id(){return 0;}

int main(){
  int N,Q;
  cin >> N >> Q;
  vector<S> ini(N+5,{0,1});
  lazy_segtree<S, op, e, F, mapping, composition, id> seg(ini);
  while(Q--){
    int typ;
    cin >> typ;
    if(typ==1){
      int l,r;
      cin >> l >> r;
      seg.apply(l,r+1,1);
    }
    else if(typ==2){
      int p;
      cin >> p;
      seg.set(p,{0,1});
    }
    else{
      int l,r;
      cin >> l >> r;
      cout << seg.prod(l,r+1).val << "\n";
    }
  }
  return 0;
}

投稿日時:
最終更新: