线段树模板

线段树详解与实现

先转载一个大佬的代码:


/** 有 n 个数和 5 种操作
add a b c:把区间[a,b]内的所有数都增加 c
set a b c:把区间[a,b]内的所有数都设为 c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a b:查询区间[a,b]的最小值
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
const long long INF = 1LL << 62;
struct Segment_tree {
    struct Node {
        int l, r;
        long long sum, max, min, set_lazy, add_lazy;
    } tre[maxn << 2];
    long long arr[maxn];
    inline void push_up(int rt) {
        if(tre[rt].l == tre[rt].r) {
            return ;
        }
        tre[rt].sum = tre[rt<<1].sum + tre[rt<<1|1].sum;
        tre[rt].max = max(tre[rt<<1].max, tre[rt<<1|1].max);
        tre[rt].min = min(tre[rt<<1].min, tre[rt<<1|1].min);
    }
    inline void push_down(int rt) {
        if(tre[rt].set_lazy) { ///if set_lazy add_lazy = 0
            tre[rt<<1].set_lazy = tre[rt].set_lazy;
            tre[rt<<1].sum = (tre[rt<<1].r - tre[rt<<1].l + 1) * tre[rt].set_lazy;
            tre[rt<<1].max = tre[rt].set_lazy;
            tre[rt<<1].min = tre[rt].set_lazy;
            tre[rt<<1|1].set_lazy = tre[rt].set_lazy;
            tre[rt<<1|1].sum = (tre[rt<<1|1].r - tre[rt<<1|1].l + 1) * tre[rt].set_lazy;
            tre[rt<<1|1].max = tre[rt].set_lazy;
            tre[rt<<1|1].min = tre[rt].set_lazy;
            tre[rt].add_lazy = 0;
            tre[rt<<1].add_lazy = tre[rt<<1|1].add_lazy = 0;
            tre[rt].set_lazy = 0;
            return ;
        }
        if(tre[rt].add_lazy) {
            tre[rt<<1].add_lazy += tre[rt].add_lazy;
            tre[rt<<1].sum += (tre[rt<<1].r - tre[rt<<1].l + 1) * tre[rt].add_lazy;
            tre[rt<<1].max += tre[rt].add_lazy;
            tre[rt<<1].min += tre[rt].add_lazy;
            tre[rt<<1|1].add_lazy += tre[rt].add_lazy;
            tre[rt<<1|1].sum += (tre[rt<<1|1].r - tre[rt<<1|1].l + 1) *
                                tre[rt].add_lazy;
            tre[rt<<1|1].max += tre[rt].add_lazy;
            tre[rt<<1|1].min += tre[rt].add_lazy;
            tre[rt].add_lazy = 0;
        }
    }
    void build(int rt,int l,int r) {
        tre[rt].l = l;
        tre[rt].r = r;
        tre[rt].set_lazy = 0;
        tre[rt].add_lazy = 0;
        if(l == r) {
            tre[rt].sum = tre[rt].max = tre[rt].min = arr[l];
            return ;
        }
        int mid = (l + r) >> 1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        push_up(rt);
    }
    void update1(int rt,int l,int r,long long val) { ///add
        push_down(rt);
        if(l == tre[rt].l && tre[rt].r == r) {
            tre[rt].add_lazy = val;
            tre[rt].sum += (tre[rt].r - tre[rt].l + 1) * val;
            tre[rt].max += val;
            tre[rt].min += val;
            return ;
        }
        int mid = (tre[rt].l + tre[rt].r) >> 1;
        if(r <= mid) {
            update1(rt<<1,l,r,val);
        } else if(l > mid) {
            update1(rt<<1|1,l,r,val);
        } else {
            update1(rt<<1,l,mid,val);
            update1(rt<<1|1,mid+1,r,val);
        }
        push_up(rt);
    }
    void update2(int rt,int l,int r,long long val) { ///set
        push_down(rt);
        if(l == tre[rt].l && tre[rt].r == r) {
            tre[rt].set_lazy = val;
            tre[rt].sum = (tre[rt].r - tre[rt].l + 1) * val;
            tre[rt].max = val;
            tre[rt].min = val;
            tre[rt].add_lazy = 0;
            return ;
        }
        int mid = (tre[rt].l + tre[rt].r) >> 1;
        if(r <= mid) {
            update2(rt<<1,l,r,val);
        } else if(l > mid) {
            update2(rt<<1|1,l,r,val);
        } else {
            update2(rt<<1,l,mid,val);
            update2(rt<<1|1,mid+1,r,val);
        }
        push_up(rt);
    }
    long long query1(int rt,int l,int r) { ///sum
        push_down(rt);
        if(l == tre[rt].l && tre[rt].r == r) {
            return tre[rt].sum;
        }
        int mid = (tre[rt].l + tre[rt].r) >> 1;
        if(r <= mid) {
            return query1(rt<<1,l,r);
        } else if(l > mid) {
            return query1(rt<<1|1,l,r);
        } else {
            return query1(rt<<1,l,mid) + query1(rt<<1|1,mid+1,r);
        }
    }
    long long query2(int rt,int l,int r) { ///max
        push_down(rt);
        if(l == tre[rt].l && tre[rt].r == r) {
            return tre[rt].max;
        }
        int mid = (tre[rt].l + tre[rt].r) >> 1;
        if(r <= mid) {
            return query2(rt<<1,l,r);
        } else if(l > mid) {
            return query2(rt<<1|1,l,r);
        } else {
            return max(query2(rt<<1,l,mid), query2(rt<<1|1,mid+1,r));
        }
    }
    long long query3(int rt,int l,int r) { ///min
        push_down(rt);
        if(l == tre[rt].l && tre[rt].r == r) {
            return tre[rt].min;
        }
        int mid = (tre[rt].l + tre[rt].r) >> 1;
        if(r <= mid) {
            return query3(rt<<1,l,r);
        } else if(l > mid) {
            return query3(rt<<1|1,l,r);
        } else {
            return min(query3(rt<<1,l,mid), query3(rt<<1|1,mid+1,r));
        }
    }
} S;

下面是我的详细线段树代码

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const ll maxn=1e5+5;
const ll inf=0x3f3f3f3f;
ll laze[maxn<<2],sum[maxn<<2];
void push_up(ll rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}//这是向上更新
void push_down(ll rt,ll l,ll r)//rt为节点值默认1,l左区间,r右区间这是向下更新懒惰标记
{
    if(laze[rt]!=-1)
    {
        ll val=laze[rt];
        ll m=(l+r)/2;
        laze[rt<<1]=val;
        sum[rt<<1]=val*(m-l+1);
        laze[rt<<1|1]=val;
        sum[rt<<1|1]=val*(r-m);
        laze[rt]=-1;
    }
}//懒惰标记
void bulid(ll rt,ll l,ll r)//l左区间,r右区间,rt为节点值默认1,建一个l-r的线段树
{
    laze[rt]=-1;
    if(l==r)
    {
        sum[rt]=0;
        return ;
    }
    ll m=l+r>>1;
    bulid(lson);
    bulid(rson);
    push_up(rt);
}//建树
void update(ll L,ll R,ll val,ll rt,ll l,ll r)//L线段树总的左区间,R线段树总的右区间val是让区间全部增加的值,l要变化的左区间,r要变化的右区间,rt为节点值默认1这是区间全部的值更新为val
{
    if(L<=l&&R>=r)
    {
        laze[rt]=val;
        sum[rt]=(r-l+1)*val;
        return ;
    }
    push_down(rt,l,r);
    ll m=l+r>>1;
    if(L<=m)
        update(L,R,val,lson);
    if(R>m)
        update(L,R,val,rson);
    push_up(rt);
}//区间全部更新成某值
ll query(ll L,ll R,ll rt,ll l,ll r)//LL线段树总的左区间,R线段树总的右区间,l要查询的左区间,r要查询的右区间,rt为节点值默认1
{
    if(L<=l&&R>=r){
        return sum[rt];
    }
    push_down(rt,l,r);
    ll m=l+r>>1,ans=0;
    if(L<=m)
        ans+=query(L,R,lson);//ans+左边的总和
    if(R>m)
        ans+=query(L,R,rson);//ans+右边的总和
    push_up(rt);
    return ans;
}//查询区间总和
void update1(ll p,ll v,ll l,ll r,ll rt)
{
	if (l == r)
	{
		sum[rt] += v;
		return ;
	}
	ll m = (l+r) >> 1;
	if (p <= m)
		update1(p, v, l, m, rt << 1);
	else
		update1(p, v, m+1, r, rt << 1 | 1);
	pushup(rt);
}//单点更新 
bulid(1,1,n);//建1-n 的树
update(l,r,l-1,1,1,n);更新l-r的变成l-1
update(p,v,l,r,1);//将p这点的值改成v
query(l,r,1,1,n);//查询l-r的总和

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-lyslyslys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值