线段树模板,c++代码实现

参考博客:

Mahr

Liangyj

线段树:是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。

建树操作
struct node
{
    long long sum,l,r,tag;
}t[666666];
long long num[666666];
void build(int p,int l,int r)
{
    t[p].l=l;
    t[p].r=r;
    if(l==r)
    {
        t[p].sum=num[l];
        return ;
    }
    int mid=(l+r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
    t[p].sum=t[2*p].sum+t[2*p+1].sum;
}
懒标记(区间求和)
void lazy(int p)
{
    if(t[p].tag)
    {
        t[2*p].sum+=t[p].tag*(t[p*2].r-t[p*2].l+1);
        t[2*p+1].sum+=t[p].tag*(t[p*2+1].r-t[p*2+1].l+1);
        t[2*p].tag+=t[p].tag;
        t[2*p+1].tag+=t[p].tag;
        t[p].tag=0;
    }
}
区间修改(加/减)
void change(int p,int x,int y,int z)
{
    if(t[p].l>=x&&t[p].r<=y)
    {
        t[p].sum+=1LL*z*(t[p].r-t[p].l+1);
        t[p].tag+=z;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    lazy(p);
    if(x<=mid)
    {
        change(p*2,x,y,z);
    }
    if(y>mid)
    {
        change(p*2+1,x,y,z);
    }
    t[p].sum=t[2*p].sum+t[p*2+1].sum;
    return ;
}
区间求和
long long sum(int p,int x,int y)
{
    if(t[p].l>=x&&t[p].r<=y)
    {
        return t[p].sum;
    }
    int mid=(t[p].l+t[p].r)/2;
    long long ans=0;
    lazy(p);
    if(x<=mid)
    {
        ans+=sum(p*2,x,y);
    }
    if(mid<y)
    {
        ans+=sum(p*2+1,x,y);
    }
    return ans;
}
单点查询
long long single_sum(int p,int x)
{
    {
        if(t[p].l==t[p].r&&t[p].l==x)
        {
            return t[p].sum;
        }
        int mid=(t[p].l+t[p].r)/2;
        lazy(p);
        long long ans=0;
        if(mid>=x)
        {
            ans+=single_sum(2*p,x);
        }
        if(mid<x)
        {
            ans+=single_sum(2*p+1,x);
        }
        return ans;
    }
}
单点修改(加/减)
void single_change (int p,int x,int z)
{
    if(t[p].l==t[p].r&&t[p].l==x)
    {
        t[p].sum+=z;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    if(mid>=x)
    {
        single_change(2*p,x,z);
    }
    if(mid<x)
    {
        single_change(2*p+1,x,z);
    }
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
区间修改(更改数值)
void lazy(int p)
{
    if(t[p].tag)
    {
        t[2*p].sum=t[p].tag*(t[p*2].r-t[p*2].l+1);//少了一个+号
        t[2*p+1].sum=t[p].tag*(t[p*2+1].r-t[p*2+1].l+1);//少了一个+号
        t[2*p].tag=t[p].tag;
        t[2*p+1].tag=t[p].tag;
        t[p].tag=0;
    }
}
void change(int p,int x,int y,int z)
{
    if(t[p].l>=x&&t[p].r<=y)
    {
        t[p].sum=1LL*z*(t[p].r-t[p].l+1);//少了一个+号
        t[p].tag=z;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    lazy(p);
    if(x<=mid)
    {
        change(p*2,x,y,z);
    }
    if(y>mid)
    {
        change(p*2+1,x,y,z);
    }
    t[p].sum=t[2*p].sum+t[p*2+1].sum;
    return ;
}
区间最大值,最小值
const int maxn = 200000+200;
struct node
{
    int l,r,maxx,minn;
}t[maxn<<2];
int num[maxn];
void build(int p,int l,int r)
{
    t[p].l=l;
    t[p].r=r;
    if(l==r)
    {
        t[p].maxx=num[l];
        t[p].minn=num[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
    t[p].minn=min(t[p<<1].minn,t[p<<1|1].minn);
}
int search_max(int pos,int x,int y)
{
    if(x<=t[pos].l&&y>=t[pos].r)
    {
        return t[pos].maxx;
    }
    int ans=-1;
    int mid=(t[pos].l+t[pos].r)>>1;
    if(x<=mid) ans=max(ans,search_max(pos<<1,x,y));
    if(y>mid) ans=max(ans,search_max(pos<<1|1,x,y));
    return ans;
}
int search_min(int pos,int x,int y)
{
    if(x<=t[pos].l&&y>=t[pos].r)
    {
        return t[pos].minn;
    }
    int ans=10000000+1;
    int mid=(t[pos].l+t[pos].r)>>1;
    if(x<=mid) ans=min(ans,search_min(pos<<1,x,y));
    if(y>mid) ans=min(ans,search_min(pos<<1|1,x,y));
    return ans;
}

你可能感兴趣的:(算法学习)