#ifndef SPARSE_SEGTREE_HPP
#define SPARSE_SEGTREE_HPP
#include<cassert>
#include<cstdint>
#include<vector>// https://suisen-cp.github.io/cp-library-cpp/library/datastructure/segment_tree/sparse_segment_tree.hpptemplate<typenameIndexType,// type of indextypenameS,// type of elementautoop,// S op(S a, S b)autoe,// S e()autoinit=[](IndexType,IndexType){returne();}// (l, r) -> init[l] * init[l+1] * ... * init[r-1]>structsparse_segtree{usingindex_type=IndexType;usingvalue_type=S;private:usingpool_index_type=uint32_t;structNode{pool_index_typech[2]{0,0};value_typedat;Node(constvalue_type&dat_):dat(dat_){}};staticinlinestd::vector<Node>pool{Node{e()}};staticpool_index_typenew_node(constvalue_type&dat){constpool_index_typeres=static_cast<pool_index_type>(pool.size());returnpool.emplace_back(dat),res;}public:sparse_segtree():sparse_segtree(0){}explicitsparse_segtree(IndexTypen_):n(n_),root(new_node(init(0,n))){}staticvoidreserve(intsiz){pool.reserve(siz);}value_typeget(index_typei)const{assert(0<=iandi<n);pool_index_typecur=root;for(index_typel=0,r=n;curandr-l>1;){index_typem=l+(r-l)/2;if(i<m)cur=pool[cur].ch[0],r=m;elsecur=pool[cur].ch[1],l=m;}returnget(cur,i,i+1);}template<typenameFun>voidapply_fun(index_typei,Fun&&fun){assert(0<=iandi<n);autorec=[&](autoself,pool_index_typecur,index_typel,index_typer)->void{if(r-l==1){pool[cur].dat=fun(get(cur,l,r));return;}constindex_typem=l+(r-l)/2;if(i<m)self(self,get_or_create_child(cur,0,l,m),l,m);elseself(self,get_or_create_child(cur,1,m,r),m,r);pool[cur].dat=op(get(pool[cur].ch[0],l,m),get(pool[cur].ch[1],m,r));};rec(rec,root,0,n);}voidset(index_typei,constvalue_type&val){apply_fun(i,[&val](constvalue_type&){returnval;});}value_typeoperator()(index_typel,index_typer)const{assert(0<=landl<=randr<=n);returnquery(root,l,r,0,n);}value_typeprod(index_typel,index_typer)const{return(*this)(l,r);}value_typeall_prod()const{returnpool[root].dat;}private:index_typen;pool_index_typeroot;value_typeget(pool_index_typenode,index_typetl,index_typetr)const{returnnode?pool[node].dat:init(tl,tr);}pool_index_typeget_or_create_child(pool_index_typenode,intindex,index_typetl,index_typetr){if(pool[node].ch[index])returnpool[node].ch[index];constpool_index_typech=new_node(init(tl,tr));returnpool[node].ch[index]=ch;}value_typequery(pool_index_typenode,index_typeql,index_typeqr,index_typetl,index_typetr)const{if(tr<=qlorqr<=tl)returne();if(notnode)returninit(std::max(ql,tl),std::min(qr,tr));if(ql<=tlandtr<=qr)returnpool[node].dat;constindex_typetm=tl+(tr-tl)/2;returnop(query(pool[node].ch[0],ql,qr,tl,tm),query(pool[node].ch[1],ql,qr,tm,tr));}};#endif // SPARSE_SEGTREE_HPP
#line 1 "segment_tree/sparse_segtree.hpp"
#include<cassert>
#include<cstdint>
#include<vector>// https://suisen-cp.github.io/cp-library-cpp/library/datastructure/segment_tree/sparse_segment_tree.hpptemplate<typenameIndexType,// type of indextypenameS,// type of elementautoop,// S op(S a, S b)autoe,// S e()autoinit=[](IndexType,IndexType){returne();}// (l, r) -> init[l] * init[l+1] * ... * init[r-1]>structsparse_segtree{usingindex_type=IndexType;usingvalue_type=S;private:usingpool_index_type=uint32_t;structNode{pool_index_typech[2]{0,0};value_typedat;Node(constvalue_type&dat_):dat(dat_){}};staticinlinestd::vector<Node>pool{Node{e()}};staticpool_index_typenew_node(constvalue_type&dat){constpool_index_typeres=static_cast<pool_index_type>(pool.size());returnpool.emplace_back(dat),res;}public:sparse_segtree():sparse_segtree(0){}explicitsparse_segtree(IndexTypen_):n(n_),root(new_node(init(0,n))){}staticvoidreserve(intsiz){pool.reserve(siz);}value_typeget(index_typei)const{assert(0<=iandi<n);pool_index_typecur=root;for(index_typel=0,r=n;curandr-l>1;){index_typem=l+(r-l)/2;if(i<m)cur=pool[cur].ch[0],r=m;elsecur=pool[cur].ch[1],l=m;}returnget(cur,i,i+1);}template<typenameFun>voidapply_fun(index_typei,Fun&&fun){assert(0<=iandi<n);autorec=[&](autoself,pool_index_typecur,index_typel,index_typer)->void{if(r-l==1){pool[cur].dat=fun(get(cur,l,r));return;}constindex_typem=l+(r-l)/2;if(i<m)self(self,get_or_create_child(cur,0,l,m),l,m);elseself(self,get_or_create_child(cur,1,m,r),m,r);pool[cur].dat=op(get(pool[cur].ch[0],l,m),get(pool[cur].ch[1],m,r));};rec(rec,root,0,n);}voidset(index_typei,constvalue_type&val){apply_fun(i,[&val](constvalue_type&){returnval;});}value_typeoperator()(index_typel,index_typer)const{assert(0<=landl<=randr<=n);returnquery(root,l,r,0,n);}value_typeprod(index_typel,index_typer)const{return(*this)(l,r);}value_typeall_prod()const{returnpool[root].dat;}private:index_typen;pool_index_typeroot;value_typeget(pool_index_typenode,index_typetl,index_typetr)const{returnnode?pool[node].dat:init(tl,tr);}pool_index_typeget_or_create_child(pool_index_typenode,intindex,index_typetl,index_typetr){if(pool[node].ch[index])returnpool[node].ch[index];constpool_index_typech=new_node(init(tl,tr));returnpool[node].ch[index]=ch;}value_typequery(pool_index_typenode,index_typeql,index_typeqr,index_typetl,index_typetr)const{if(tr<=qlorqr<=tl)returne();if(notnode)returninit(std::max(ql,tl),std::min(qr,tr));if(ql<=tlandtr<=qr)returnpool[node].dat;constindex_typetm=tl+(tr-tl)/2;returnop(query(pool[node].ch[0],ql,qr,tl,tm),query(pool[node].ch[1],ql,qr,tm,tr));}};