线段树
构建模块
build
update
add
query
push_down
核心
tree[node]=arr[l];
tree[node] = tree[lc]+tree[rc];
static void build(int node,int l,int r){
if(l==r){
tree[node]=arr[l];
return;
}
int mid = (r+l)>>1;
int lc = 2*node+1;
int rc = 2*node+2;
build(lc,l,mid);
build(rc,mid+1,r);
tree[node] = tree[lc]+tree[rc];
}
lazy[node]+=add;
tree[node]+= (long) (R - L + 1) *add;
if(mid>=l){
add(add, l, r, L, mid, lc);
}
if(r>mid){
add(add, l, r, mid+1, R, rc);
}
static void add(int add, int l, int r, int L, int R, int node){
if(l<=L&&r>=R){
lazy[node]+=add;
tree[node]+= (long) (R - L + 1) *add;
return;
}
push_down(node, L, R);
int mid = (L+R)>>1;
int lc = 2*node+1;
int rc = 2*node+2;
if(mid>=l){
add(add, l, r, L, mid, lc);
}
if(r>mid){
add(add, l, r, mid+1, R, rc);
}
tree[node] = tree[lc]+tree[rc];
}
}
long sum=0;
if(mid>=l) sum+=query(l,r,L,mid,2*node+1);
if(mid<r) sum+=query(l,r,mid+1,R,2*node+2);
return sum;
static long query(int l,int r,int L,int R,int node)
{
if(l<=L&&r>=R)
return tree[node]; //当所查找的区间覆盖当前区间时
push_down(node,L,R);
int mid=(L+R)>>1;
long sum=0;
if(mid>=l) sum+=query(l,r,L,mid,2*node+1);
if(mid<r) sum+=query(l,r,mid+1,R,2*node+2);
return sum;
}
lazy[node]!=0
tree[lc]+=lazy[node]*(mid-L+1);
tree[rc]+=lazy[node]*(R-mid);
static void push_down(int node,int L,int R){
if(lazy[node]!=0){
int mid = (L+R)>>1;
int lc = 2*node+1;
int rc = 2*node+2;
lazy[lc]+=lazy[node];
lazy[rc]+=lazy[node];
tree[lc]+=lazy[node]*(mid-L+1);
tree[rc]+=lazy[node]*(R-mid);
lazy[node]=0;
}
}
// L~R 所有的值变成C
// l~r rt
public void update(int L, int R, int C, int l, int r, int rt) {
if (L <= l && r <= R) {
update[rt] = true;
change[rt] = C;
sum[rt] = C * (r - l + 1);
lazy[rt] = 0;
return;
}
// 当前任务躲不掉,无法懒更新,要往下发
int mid = (l + r) >> 1;
pushDown(rt, mid - l + 1, r - mid);
if (L <= mid) {
update(L, R, C, l, mid, rt << 1);
}
if (R > mid) {
update(L, R, C, mid + 1, r, rt << 1 | 1);
}
pushUp(rt);
}
需要修改pushDown
// 之前的,所有懒增加,和懒更新,从父范围,发给左右两个子范围
// 分发策略是什么
// ln表示左子树元素结点个数,rn表示右子树结点个数
private void pushDown(int rt, int ln, int rn) {
if (update[rt]) {
//更新信号下传
update[rt << 1] = true;
update[rt << 1 | 1] = true;
//改变的值下传
change[rt << 1] = change[rt];
change[rt << 1 | 1] = change[rt];
//懒标记失效
lazy[rt << 1] = 0;
lazy[rt << 1 | 1] = 0;
//当前和改变
sum[rt << 1] = change[rt] * ln;
sum[rt << 1 | 1] = change[rt] * rn;
//当前节点完成
update[rt] = false;
}
if (lazy[rt] != 0) {
lazy[rt << 1] += lazy[rt];
sum[rt << 1] += lazy[rt] * ln;
lazy[rt << 1 | 1] += lazy[rt];
sum[rt << 1 | 1] += lazy[rt] * rn;
lazy[rt] = 0;
}