线段树;区间求和优化
线段树构造:
线段树:4*空间
第一种:
#define maxn 100007//元素个数
int SegTree[maxn << 2];//线段树
// int lazy[maxn << 2];//延迟更新
int A[maxn];//原是数组
第二种:结构体
void pushup(int rt) {//更新节点信息
segtree[rt].val = segtree[rt << 1].val + segtree[rt << 1 | 1].val;//rt=左儿子+右儿子
}
void build(int l, int r, int rt) {
if(l == r) {//叶节点
segtree[rt].val = A[l];
return ;
}
int m = (l + r) / 2;
build(l, m, rt * 2);//左
build(m + 1, r, rt * 2 + 1);//右
pushup(rt);//回溯,向上更新
}
单点更新:
//单点更新:A[i] += x;
//准备修改的位置i,准备加上去的值x,节点区间l,r,存储下标为rt
void update(int i, int x, int l, int r, int rt) {//即查找然后修改
if(l == r) {
segtree[rt].val += x;
return ;
}
int m = (l + r) >> 1;
//改变某一个值,所以结果一定在某子树左边or右边
if(i <= m) update(i, c, l, m, rt << 1);
else update(i, c, m + 1, r, rt << 1 | 1);
pushup(rt);
}
区间单点查询:
// 区间查询:
int query(int a, int b, int l, int r, int rt) {//a,b为查找区间,l,r为当前下标,rt为当前节点
if(a <= l && r <= b) return segtree[rt].val;//包含
if(a > r || b < l) return 0;//完全无关
//接下来递归处理
int m = (l + r) >> 1;
//写法1:
// int ans = 0;
// if(a <= m) ans += query(a, b, l, m, rt << 1);
// if(b > m) ans += query(a, b, m + 1, r, rt << 1 | 1);
// return ans;
//写法2:
return query(a, b, l, m, rt << 1) +
query(a, b, m + 1, r, rt << 1 | 1);
}
区间更新:
//区间更新:会涉及到回溯(节点间关系改变),效率低,此时引入惰性标记
//惰性标记:记录更新(动态),查到哪里更新到哪里
#define maxn 100007
int A[maxn];
struct segtreenode {
int val, lazy;//惰性标记
}
segtree[maxn << 2];
//对应构造
void build(int l, int r, int rt) {
segtree[rt].lazy = 0;
if(l == r) {//叶节点
segtree[rt].val = A[l];
return ;
}
int m = (l + r) / 2;
build(l, m, rt * 2);//左
build(m + 1, r, rt * 2 + 1);//右
pushup(rt);//回溯,向上更新
}
区间更新:
void pushdown(int rt, int ln, int rn) {//ln,rn为左右子树区间大小
if(segtree[rt].lazy) {//下推标记
//孩子继承父亲lazy
segtree[rt << 1].lazy += segtree[rt].lazy;
segtree[rt << 1 | 1].lazy += segtree[rt].lazy;
//修改对应的值
segtree[rt << 1].val += segtree[rt].lazy * ln;
segtree[rt << 1 | 1].val += segtree[rt].lazy * rn;
segtree[rt].lazy = 0;//清楚本节点标记
}
}
void update(int a, int b, int x, int l, int r, int rt) {
if(a <= l && r <= b) {
segtree[rt].val += x * (r - l + 1);//更新区间和
segtree[rt].lazy += x;//根据操作为:累加or赋值
return ;
}
int m = (l + r) >> 1;
pushdown(rt, m - l + 1, r - m);//下推之后,才更新子节点
if(a <= m) update(a, b, x, l, m, rt << 1);
if(b > m) update(a, b, x, m + 1, r, rt << 1 | 1);
pushup(rt);//更新本节点信息
}
区间(区间)查询:因存在惰性lazy,所以要处理lazy
通过下推,来让子节点信息准确
void update(int a, int b, int x, int l, int r, int rt) {
if(a <= l && r <= r) {
segtree[rt].val += x * (r - l + 1);//更新数字和,向上保证正确
segtree[rt].lazy += x;//支持累加or赋值
return ;
}
int m = (l + r) >> 1;
pushdown(rt, m - l + 1, r - m);//下推,准确更新子节点
if(a <= m) update(a, b, x, l, m, rt << 1);
if(b > m) update(a, b, x, m + 1, r, rt << 1 | 1);
pushup(rt);//更新本节点
}
int query(int a, int b, int l, int r, int rt) {
if(a <= l && r <= b) return segtree[rt].val;
if(a > r || b < l) return 0;
int m = (l + r) >> 1;
pushdown(rt, m - l + 1, r - m);//下推,使子节点信息准确
return query(a, b, l, m, rt << 1) +
query(a, b, m + 1, r, rt << 1 | 1);
}
浙公网安备 33010602011771号