迭代型線段樹 區間修改
遞迴型的線段樹能做到區間修改,迭代型的當然也可以!
Last updated
遞迴型的線段樹能做到區間修改,迭代型的當然也可以!
Last updated
for(l += n-1, r += n-1; l < r; l >>= 1, r >>= 1){
//Change函式是幫助我們拿來更新節點答案的函式
if(l&1) change(l++, val);
if(r&1) change(--r, val);
}void push(int i){
for(int h = __lg(i); h >= 1; h--){
int idx = i >> h;
if(!tag[idx]) continue;
change(idx<<1, tag[idx]);
change(idx<<1|1, tag[idx]);
tag[idx] = 0;
}
}void pull(int i){
for(i>>=1 ; i >= 1; i >>= 1){
//要記得加上標記,因為標記還沒下推
tr[i] = combine(tr[i<<1],tr[i<<1|1])+tag[i];
}
}const int N = 1e5+5;
int tr[N<<1], tag[N], arr[N];
int n;
int combine(int a, int b){
return min(a,b);
}
void init(){
for(int i = 1;i <= n;i++){
tr[i+n-1] = arr[i];
}
for(int i = n-1;i >= 1;i--){
tr[i] = combine(tr[i<<1], tr[i<<1|1]);
}
}
void change(int idx, int val){
tr[idx] += val;
if(idx < n) tag[idx] += val;
}
void push(int i){
for(int h = __lg(i); h >= 1; h--){
int idx = i >> h;
if(!tag[idx]) continue;
change(idx<<1, tag[idx]);
change(idx<<1|1, tag[idx]);
tag[idx] = 0;
}
}
void pull(int i){
for(i>>=1 ; i >= 1; i >>= 1){
tr[i] = combine(tr[i<<1],tr[i<<1|1])+tag[i];
}
}
void modify(int l, int r, int val){
int tl = l, tr = r; //紀錄原本的 l, r
push(l+n-1), push(r-1+n-1);
for(l += n-1, r += n-1; l < r; l >>= 1, r >>= 1){
if(l&1) change(l++, val);
if(r&1) change(--r, val);
}
pull(tl+n-1), pull(tr-1+n-1);
}
int query(int l, int r){
push(l+n-1), push(r-1+n-1);
int res = 1e18;
for(l+=n-1, r+=n-1;l < r;l>>=1,r>>=1){
if(l&1) res = combine(res, tr[l++]);
if(r&1) res = combine(res, tr[--r]);
}
return res;
}void change(int idx, int val, int h){
tr[idx] += val * (1<<h);
if(idx < n) tag[idx] += val;
}
void pull(int i){
int h;
for(h = 1, i>>=1 ; i >= 1; i >>= 1){
tr[i] = combine(tr[i<<1],tr[i<<1|1]) + tag[i] * (1<<h);
}
}
void modify(int l, int r, int val){
int tl = l, tr = r, h = 0;
push(l+n-1), push(r-1+n-1);
for(l += n-1, r += n-1; l < r; l >>= 1, r >>= 1, h++){
if(l&1) change(l++, val, h);
if(r&1) change(--r, val, h);
}
pull(tl+n-1), pull(tr-1+n-1);
}