线段树解决的主要问题:1 单点更新,区间查询 2 区间更新,单点查询 3 区间更新,区间查询
线段树的本质是一棵二叉树,线段树的每一个节点记录的是一段区间的信息。
e.g. 对于长度为5的数组a[1]~a[5]
[1,5]
[1,3] [4,5] 对于任一非叶子节点,若该区间为[L,R],则
[1,2] [3,3] [4,4] [5,5] 左儿子为[L,(L+R)/2]
右儿子为[(L+R)/2+1,R]
对于任一节点a[k],
它的左儿子为a[2*k]
它的右儿子为a[2*k
线段树空间应开为原数组长度的4倍
课件中的方法:
lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示
PushUP(int rt)是把当前结点的信息更新到父结点
PushDown(int rt)是把当前结点的信息更新给儿子结点
建树
void PushUP(int rt) {
MAX[rt] = MAX[rt<<1] + MAX[rt<<1|1];
}//具体问题具体分析
void build(int l,int r,int rt) {
if (l == r) {
scanf("%d",&MAX[rt]);
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUP(rt);
}// build(1,n,1)
更新
void update(int p,int sc,int l,int r,int rt) {更新的输的位置 输入跟新的树
if (l == r) {
MAX[rt] = sc;//具体问题具体分析
return ;
}
int m = (l + r) >> 1;
if (p <= m) update(p , sc , lson);
else update(p , sc , rson);
PushUP(rt);
}
查询
int query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return MAX[rt];
}
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret = max(ret , query(L , R , lson));具体问题具体分析
if (R > m) ret = max(ret , query(L , R , rson));
return ret;
}