コード例は抽象化してません
あしからず
1.がちがちの動的セグ木を使う
コピペありの環境なら一番いいです
思想としてはポインタを使って必要になった時にノードを作るです
構築O(1)です
template<typename T>
struct dynamic_segment{
struct node;
using np=node*;
struct node{
np ch[2]={0,0};
T val=0;
};
np root=new node();
np add(int64_t l,int64_t r,int64_t x,T val,np t){
if(!(l<=x&&x<r))return t;
if(!t)t=new node();
t->val+=val;
if(r-l==1)return t;
int64_t m=(l+r)/2;
t->ch[0]=add(l,m,x,val,t->ch[0]);
t->ch[1]=add(m,r,x,val,t->ch[1]);
return t;
}
T get(int64_t l,int64_t r,int64_t a,int64_t b,np t){
if(!t)return 0;
if(b<=l||r<=a)return 0;
if(a<=l&&r<=b)return t->val;
int64_t m=(l+r)/2;
return get(l,m,a,b,t->ch[0])+get(m,r,a,b,t->ch[1]);
}
void add(int64_t x,T val){root=add(0,1LL<<32,x,val,root);}
T get(int64_t l,int64_t r){return get(0,1LL<<32,l,r,root);}
};
2.急造動的セグ木を使う
クエリになりますが、ポインタに慣れてない人はこちらを使うのもいいかも
ICPC等で、計算量に余裕がある場合もおすすめ
普段配列を使うところをmapに置き換えるだけです
unordered_mapにすればになるのでちょっと速くなるかも知れないです
構築O(1)です
template<typename T>
struct dynamic_segment{
map<int64_t,T>node;
constexpr static int64_t sz=1LL<<32;
void add(int64_t x,T val){
x+=sz;
while(x){
node[x]+=val;
x/=2;
}
}
T get(int64_t l,int64_t r){
l+=sz;r+=sz;
T res=0;
while(l<r){
if(l&1)res+=node[l++];
if(r&1)res+=node[--r];
l/=2;r/=2;
}
return res;
}
};
3.セグ木を使いまわす
10^5要素のセグ木を10^5回のループ毎に作らなければいけないみたいなパターンで使えます
使ったノードを初期値に戻す事で使いまわします
template<typename T>
struct dynamic_segment{
vector<T>node;
vector<int>used;
int sz=1,n;
dynamic_segment(int n):n(n){
while(sz<n)sz*=2;
node.resize(sz*2,0);
}
void add(int64_t x,T val){
x+=sz;
while(x){
node[x]+=val;
used.push_back(x);
x/=2;
}
}
T get(int64_t l,int64_t r){
l+=sz;r+=sz;
T res=0;
while(l<r){
if(l&1)res+=node[l++];
if(r&1)res+=node[--r];
l/=2;r/=2;
}
return res;
}
void clear(){
for(auto e:used)node[e]=0;
used.clear();
}
};