1点更新・区間演算(※)が1回当たり O(logN) 出来るデータ構造。
集合 S とその上の二項演算 •: S × S → S が与えられた時、
※単位減は演算の前後で値が変化しない元のこと。足し算における0、 掛け算における1。
template<typename S,S(*op)(S,S),S(*e)()>
struct SegTree{
SegTree() : n(0){}
explicit SegTree(ll _n){
n = _n;
log2 = 0;
while((1LL << log2) < n)log2++;
size = 1LL << log2;
data = vector<S>(2*size,e());
}
void set(ll i,S x){
// dataの葉のidxを参照する為に足す
i += size;
// dataの中で更新を反映させるべきnodeを捜査
// ※完全二分木を書けば分かる
data[i] = x; // data[i]はupdate()では不可(葉を参照してるから)
while(i > 1){
i /= 2;
update(i);
}
}
void update(ll i){
data[i] = op(data[2*i],data[2*i+1]);
}
S prod(ll l,ll r){
l += size, r += size;
S sml = e(),smr = e();
while(l < r){
// ここの処理はmemo参照
if(l & 1)sml = op(sml,data[l++]);
if(r & 1)smr = op(data[--r],smr);
l /= 2, r /= 2;
}
return op(sml,smr);
}
S all_prod(){
return data[1];
}
private:
ll size;
ll log2;
ll n;
vector<S> data;
};