模板:线段树(2)区间修改

好像叫做懒操作来着。。还是叫延迟修改更高大上一点吧

  • 增加操作
//区间修改

/*两种操作
Add(L ,R ,v):把A[L],A[L+1],...,A[R]的值全部增加v
Query(L ,R )计算子序列A[L],A[L+1],...,A[R]的元素和,最小值和最大值
*/

//修改/查询的范围均为[y1,y2]

//维护节点o,它对应区间[L,R]
void maintain(int o, int l, int r) {
    int lc = o*2, rc = o*2+1;
    if(r > l) { //考虑左右子树
        sumv[o] = sumv[lc] + sumv[rc];
        minv[o] = min(minv[lc], minv[rc]);
        maxv[o] = max(maxv[lc], maxv[rc]);
    }
    minv[o] += addv[o];
    maxv[o] += addv[o];
    sumv[o] += addv[o] * (r-l+1);//考虑add操作
    if(r==l) addv[o] = 0;
}

void update(int o, int l, int r) {
    int lc = o*2, rc = o*2+1;
    if(y1 <= l && r <= y2) { //递归边界
        addv[o] += v;        //累加边界的add值
    }
    else {
        int m = l + (r-l)/2;
        if(y1 <= m) update(lc, l, m);
        if(y2 > m) update(rc, m+1, r);
    }
    maintain(o, l, r);  //递归结束前重新计算本节点的附加信息
}

int _min, _max, _sum;   //全局变量,目前位置的最小值、最大值和累加值

void query(int o, int l, int r,int add){  //add为当前节点延迟修改值
    if(y1 <= l && y2 >= r) {  //递归边界:用边界区间的附加信息更新答案
        _sum += sumv[o] + add * (r-l+1);
        _min = min(_min, minv[o] + add);
        _max = max(_max, maxv[o] + add);
    }
    else {  //递归统计,累加参数add
        int m = l + (r-l)/2;
        if(y1 <= m) query(o*2, l, m, add + addv[o]);
        if(y2 > m) query(o*2+1, m+1, r, add + addv[o]);
    }
}
  • 设置操作
/*两种操作:
    Set(l, r, v): 把A[l],A[l+1],,...,A[r]的值全部修改为v(v>=0)
    Query(l, r): 计算子序列A[l],A[l+1],...,A[r]的元素和、最小值和最大值
*/

void update(int o, int l, int r) {
    int lc = o*2, rc = o*2+1;
    if(y1 <= l && y2 >= r) { //标记修改
        setv[o] = v;
    }
    else {
        pushdown(o);
        int m = l + (r-l)/2;
        if(y1 <= m) update(lc, l, m); else maintain(lc, l, m);
        if(y2 > m) update(rc, m+1, r); else maintain(rc, m+1, r);
    }
    maintain(o, l, r);
}

//标记传递
void pushdown(int o){
    int lc = o*2, rc = o*2+1;
    if(setv[o] >= 0) { //本节点有标记才传递。 注意本题中set值非负,所以-1代表没有标记
        setv[lc] = setv[rc] = setv[o];
        setv[o] = -1; //消除本节点标记
    }
}

void query(int o, int l, int r) {
    if(setv[o] >= 0) {  //递归边界1: 有set标记
        _sum += setv[o] * (min(r, y2)-max(l, y1)+1);
        _min = min(_min, setv[o]);
        _max = max(_max, setv[o]);
    }
    else if(y1 <= l && y2 >= r) {  //递归边界2:边界区间
        _sum += sumv[o];
        _min = min(_min, setv[o]);
        _max = max(_max, setv[o]);
    }
    else {                  //递归统计
        int m = l + (r-l)/2;
        if(y1 <= m) query(o*2, l, m);
        if(y2 > m) query(o*2+1, m+1, r);
    }
}

上面set操作的maintain貌似需要重写一下,等我找一道题目试一下再修改。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值