线段树基础知识+单点更新、区间更新模板

版权声明:本人大三在读,有错误烦请指正,共同进步- ( ゜- ゜)つロ 乾杯~点赞请按右上角,转载请标明出处: https://blog.csdn.net/hzyhfxt/article/details/85679682

本文根据网页链接的视频进行学习,感谢up主!

线段树适用情况

题目给了一个数组(例如[1,5,4,1,6],通常数据比较多),对其中的部分区间进行多次更新,然后对部分区间进行多次查询(查询区间内的最大值/最小值/和),普通做法会超时,应使用线段树来做~

抽象化建树

建立二叉树,把数组存到二叉树中去

(例如,

然后从叶子结点很容易得到我们需要查询的内容,然后不断将查询的结果往上传

(例如区间内的最大值/最小值/和,

更新数据

更新a[2] = 3,查询相应的叶子结点更新数据,然后更新叶子结点的区间内的最大值/最小值/和,原路返回往上传更新区间查询的值

区间查询

例如查询sum(3,5),即数组中a[3],a[4],a[5]的和,完全包含的节点就不用再往下查询,获取该节点的信息即可


 【单点更新,区间查询求和模板 】

模板源自博主链接例题hduoj1166

//注意:
//下标从1开始;
//使用方法:
//build(1, n);
//update(pos, val, 1, n); 更新树中下标为pos的叶子节点值增加val
//query(l, r, 1, n); 查询[l ,r]区间值之和

const int maxn = 5e4+5;
int a[maxn];
// -----线段树单点更新模板------
#define lson l,m,rt<<1          //预定子左树
#define rson m+1,r,rt<<1|1      //预定右子树
int sum[maxn<<2];//表示节点,需要开到最大区间的四倍
void pushup(int rt){
    //对于编号为rt的节点,他的左右节点分别为rt<<1和rt<<1|1
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt=1){
    //建树操作,生成一个区间为l~r的完全二叉树
    
    //如果到底,则线段长度为0,表示一个点,输入该点的值
    if (l==r) {
        sum[rt]=a[l];
        return;
    }
    
    //准备子树
    int m=(l+r)>>1;
    
    //对当前节点建立子树
    build(lson);
    build(rson);
    
    //由底向上求和
    pushup(rt);
}
void update(int pos,int val,int l,int r,int rt=1){
    //pos为更新的位置 val为增加的值,正则加,负则减
    //l r为区间的两个端点值
    
    //触底,为一个点的时候,该节点值更新
    if (l==r) {
        sum[rt]+=val;
        return;
    }
    int m = ( l + r ) >> 1;
    if (pos<=m)     //pos在左子树的情况下,对左子树进行递归
        update(pos, val, lson);
    else            //pos在右子树的情况下,对右子树进行递归
        update(pos, val, rson);
    
    //更新包含该点的一系列区间的值
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt=1){
    // L~R为被查询子区间 l~r为“当前”树的全区间
    if (L<=l&&r<=R)    //子区间包含“当前”树全区间
        return sum[rt]; //返回该节点包含的值
    int m=(l+r)>>1;
    int res=0;
    if (L<=m)       //左端点在左子树内
        res+=query(L, R, lson);
    if (R>m)        //右端点在右子树内
        res+=query(L, R, rson);
    return res;
}

 【区间更新模板 】

例题链接uestcOJ秋实大哥与花(线段树)

//使用方法:
//  build(1,1,n);
//  update(1,le,r,v);//le~r范围内的值更新为v
//  query(1,le,r);//查询le~r范围内的值的和

typedef long long ll;
const int maxn = 1e5+5;
int a[maxn];
struct node
{
    int l,r;
    ll sum,lazy;
    void update(int x)
    {
        sum += 1ll*(r-l+1)*x;
        lazy += x;
    }
}tree[maxn*4];
void push_up(int x)
{
    tree[x].sum = tree[x<<1].sum + tree[x<<1|1].sum;
}
void push_down(int x)
{
    int lazyval = tree[x].lazy;
    if(lazyval)
    {
        tree[x<<1].update(lazyval);
        tree[x<<1|1].update(lazyval);
        tree[x].lazy=0;
    }
}
void build(int x,int l,int r)
{
    tree[x].l = l;
    tree[x].r = r;
    tree[x].sum = tree[x].lazy = 0;
    if(l == r)
    {
        tree[x].sum = a[l];
    }
    else
    {
        int mid = (l+r)/2;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        push_up(x);
    }
}
void update(int x,int l,int r,ll val)
{
    int L = tree[x].l;
    int R = tree[x].r;
    if(l<=L &&  R<=r)//l..(L..R)..r
    {
        tree[x].update(val);
    }
    else
    {
        push_down(x);
        int mid = (L+R)/2;
        if(mid >= l)
            update(x<<1, l, r, val);
        if(r > mid)
            update(x<<1|1, l, r, val);
        push_up(x);
    }
}
ll query(int x,int l, int r)
{
    int L = tree[x].l;
    int R = tree[x].r;
    if(l<=L &&  R <= r)
    {
        return tree[x].sum;
    }
    else
    {
        push_down(x);
        ll ans = 0;
        int mid = (L+R)/2;
        if(mid >= l)
            ans += query(x<<1, l, r);
        if(r > mid)
            ans += query(x<<1|1, l, r);
        push_up(x);
        return ans;
    }
    
}

猜你喜欢

转载自blog.csdn.net/hzyhfxt/article/details/85679682