hiho 20 使用线段树进行区间修改

问题描述

线段树可以快速得对一段区间做修改操作,时间复杂度为O(logN)

实现

在每个节点处增加一个lazyTag,当节点所在的区间都被修改时,将修改记录在lazyTag中,不用再往下递归。当查询或者下次修改到改节点时,将lazyTag下移。

#include <bits/stdc++.h>
using namespace std;
enum {maxn = 1<<17};
struct Node{
    int all;
    int lazyTag;
};
Node st[maxn<<1];
int p[maxn];
void pushDown(int rt, int L, int R)
{
    if (st[rt].lazyTag && L!=R)
    {
        int m = L+(R-L)/2;
        st[rt<<1].lazyTag = st[rt<<1|1].lazyTag = st[rt].lazyTag;
        st[rt<<1].all = (m+1-L) * st[rt].lazyTag;
        st[rt<<1|1].all = (R-m)* st[rt].lazyTag;
        st[rt].lazyTag = 0;
    }
}
void build(int rt, int L, int R)
{
    st[rt].lazyTag = 0;
    if (L==R)
    {
        st[rt].all = p[L];
    }
    else{
        int m = L+(R-L)/2;
        build(rt<<1, L, m);
        build(rt<<1|1, m+1, R);
        st[rt].all = st[rt<<1].all + st[rt<<1|1].all;
    }
}
int ql, qr;
int q(int rt, int L, int R)
{
    if (ql <= L && R <= qr)
        return st[rt].all;
    if (R < ql || qr<L)
        return 0;
    pushDown(rt, L, R);
    int m = L+ (R-L)/2;
    return q(rt<<1, L, m) + q(rt<<1|1, m+1, R);
}
int ul, ur, uv;
void update(int rt, int L, int R)
{
    if (ul <= L && R <= ur)
    {
        st[rt].all = (R+1-L) * uv;
        st[rt].lazyTag = uv;
        return ;
    }
    if (R< ul || ur<L)
        return;
    pushDown(rt, L, R);
    int m = L+(R-L)/2;
    update(rt<<1, L, m);
    update(rt<<1|1, m+1, R);
    st[rt].all = st[rt<<1].all + st[rt<<1|1].all;
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i=1; i<= n; i++)
    {
        scanf("%d", &p[i]);
    }
    build(1, 1, n);
    int m;
    scanf("%d", &m);
    for (int i=0; i< m; i++)
    {
        int o;
        scanf("%d", &o);
        if (o)
        {
            scanf("%d %d %d", &ul, &ur, &uv);
            update(1, 1, n);
        }else{
            scanf("%d %d", &ql, &qr);
            printf("%d\n", q(1, 1, n));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值