OVSolitario-io

导航

线段树;区间求和优化

线段树构造:

线段树: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);
}

posted on 2025-10-27 19:13  TBeauty  阅读(0)  评论(0)    收藏  举报