线段树【单点更新,区间更新,区间查询,最值查询】

 写了一下午的线段树,也算是做个总结吧。下面的区间更新写了两种,一种是没有用到懒操作一种是用了的。懒操作主要是在区间更新的时候用到,下面求区间和 and 区间最值都是要用到懒操作的

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 5e4;
int N,a[Max];
typedef struct Tree{
    int L,R;
    int sum;
    int lazy;//需要增加的值
    int Max;
};
Tree tree[Max<<2];
typedef long long ll;
void push_up(int x)
{
    tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
    tree[x].Max = max(tree[x<<1].Max,tree[x<<1|1].Max);
}
void push_down(int x,int num)
{
    if(tree[x].lazy){
        tree[x<<1].sum+=tree[x].lazy*(num-(num/2));//每个点需要更新的值*个数
        tree[x<<1|1].sum += tree[x].lazy*(num/2);

        tree[x<<1].Max = tree[x].Max+tree[x].lazy;
        tree[x<<1|1].Max = tree[x].Max+tree[x].lazy;

        tree[x<<1].lazy += tree[x].lazy;
        tree[x<<1|1].lazy+=tree[x].lazy;
        tree[x].lazy = 0;
    }
}
void build(int x,int l,int r)
{
    tree[x].L = l;
    tree[x].R = r;
    tree[x].sum = 0;
    tree[x].lazy=0;
    if(l==r){
        tree[x].sum=a[l];
        tree[x].Max=a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    push_up(x);
}

void update(int x,int pos,int val)
{
    int L = tree[x].L,R=tree[x].R;
    if(L==R)
    {
        tree[x].sum += val;
        tree[x].Max += val;
        return;
    }
    int mid = (L+R)>>1;
    if(pos<=mid)
        update(x<<1,pos,val);
    else
        update(x<<1|1,pos,val);
    push_up(x);
}
void update2(int x,int l,int r,int val)//将区间[l,r]的值都加上val【区间更新】
{
    int L = tree[x].L,R=tree[x].R;
    if(L==R){
        tree[x].sum+=val;
        tree[x].Max+=val;
        return;
    }
    int mid = (L+R)>>1;
    if(l<=mid){
        update2(x<<1,l,r,val);
    }
    if(mid<r){
        update2(x<<1|1,l,r,val);
    }
    push_up(x);
}
void update3(int x,int l,int r,int val)
{
    int L= tree[x].L,R=tree[x].R;
    if(l<=L&&r>=R){
        tree[x].lazy+=val;
        tree[x].Max+=val;
        tree[x].sum += (ll)val*(R-L+1);
        return;
    }
    push_down(x,R-L+1);
    int mid = (L+R)>>1;
    if(l<=mid) update3(x<<1,l,r,val);
    if(mid<r) update3(x<<1|1,l,r,val);
    push_up(x);
}
int query(int x,int l,int r)//区间和查询
{
    int ans = 0;
    int L = tree[x].L, R = tree[x].R;
    if(l<=L&&r>=R)
        return tree[x].sum;
    push_down(x,R-L+1);
    int mid = (l+r)>>1;
    if(l<=mid)
        ans+=query(x<<1,l,r);
    if(mid<r)
        ans+=query(x<<1|1,l,r);
    return ans;
}
int searchMax(int x,int l,int r)//区间最值查询
{
    int L = tree[x].L,R = tree[x].R;
    if(l<=L&&R<=r){
       return tree[x].Max;
    }
    push_down(x,R-L+1);
    int mid = (l+r)>>1;
    int res = -99999;
    if(l<=mid) res=max(res,searchMax(x<<1,l,r));
    if(mid<r) res = max(res,searchMax(x<<1|1,l,r));
    return res;
}
int main()
{
    string str;
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        scanf("%d",&a[i]);
    build(1,1,N);
    while(1)
    {
        cin>>str;
        if(str[0]=='e')
            break;
        else if(str[0]=='1'){//单点更新
            int pos,val;
            scanf("%d%d",&pos,&val);
            update(1,pos,val);
        }else if(str[0]=='2'){//不用懒标记的区间更新
            int l,r,val;
            scanf("%d%d%d",&l,&r,&val);
            update2(1,l,r,val);
        }else if(str[0]=='3'){//使用懒标记的区间更新
            int l,r,val;
            scanf("%d%d%d",&l,&r,&val);
            update3(1,l,r,val);
        }else if(str[0]=='4'){//区间最值查询
            int l,r;
            scanf("%d%d",&l,&r);
            int ans = searchMax(1,l,r);
            printf("%d
",ans);
        }else{//query
            int left,right;
            scanf("%d%d",&left,&right);
            int ans = query(1,left,right);
            printf("%d
",ans);
        }
    }
    return 0;
}

用了懒标记的和没有用懒标记的不要混在一起使用。

原文地址:https://www.cnblogs.com/qie-wei/p/10160180.html