线段树的内涵:用数组模拟树,每个节点掌控一个L,R区间,该节点的值为L,R的“总”信息;
每个节点有俩个左右孩子;
线段树的适用条件: 总信息可以由左孩子以及右孩子的总信息加工而成,而这个加工函数就是
up(i),以及 search()的关键
线段树的修改理解:不断通过二分,向下找出所有包含目标子区间的节点,然后对这个节点的值进行修改;
线段树查询理解:不断通过二分找到所有子区间,利用加工原理,汇合出总答案;
线段树区间修改原理: 如果一个区间修改完全覆盖一个子区间,那么不必继续向下搜索,而是懒住,一但有向下访问,那么一层一层下放;即只有区间被访问子区间才需下放;
线段树的关键: 关键在于加工函数以及修改逻辑;
加工:节点信息到底怎样由孩子信息加工而成;区间和,则孩子信息和,区间最大值则孩子最大值,
修改:区间增减,区间乘,区间重置,
代码:
void up(int i){
tree[i]=tree[ls]+tree[rs];
}
int s(int i,int jl,int jr,int l,int r){
if(l>=jl&&r<=jr)return tree[i];
down(i,l,r);
int mid=(l+r)/2;
int res=0;
if(mid>=l)res+=s(ls,jl,jr,l,mid);
if(mid<r)res+=(rs,jl,jr,mid+1,r);
return res;
}// 可见 主要逻辑在于 加工函数
void add(int i,int jl,int jr,int l,int r,int k){
if(l>=jl&&r<=jr){
tree[i]+=(r-l+1)*k;
lazy[i]+=k;
return;
}
down(i,l,r);
int mid=(l+r)/2;
if(mid>=l)add(ls,jl,jr,l,mid,k);
if(mid<r)add(rs,jl,jr,mid+1,r,k);
up(i);
}
void down(int i,int l,int r){
if(lazy[i]){
int mid=(l+r)/2;
add(ls,l,r,l,mid,lazy[i]);
add(rs,l,r,mid+1,r,lazy[i]);
lazy[i]=0;
}
}// 主要逻辑在于修改逻辑