【模板】线段树

蓝咒 提交于 2019-11-28 06:05:37

一.最基础的线段树:支持区间加减修改,区间查询。

  其实两个差分树状数组也可以搞定这个事情,不过还是线段树这样更加直观一点。

  建议初步接触线段树的同学先看主程序再看函数,然后有需要可以手动模拟一下,有助于理解每个函数的作用~

#include<bits/stdc++.h>
using namespace std;
struct SegTree
{
    int l,r;
    long long sum,Lazy;
}Tree[400040];
int n,m,x,y,z,opt;
long long a[100010];

void push_up(int k)
{
    Tree[k].sum=Tree[k<<1].sum+Tree[k<<1|1].sum;
}
void Build(int k,int l,int r)
{
    Tree[k].l=l;
    Tree[k].r=r;
    if(l==r)
    {
        Tree[k].sum=a[l];
        return;
    }
    int mid=l+r>>1;
    Build(k<<1,l,mid);
    Build(k<<1|1,mid+1,r);
    push_up(k);
}
void push_down(int k)
{
    if(Tree[k].Lazy)
    {
        Tree[k<<1].sum+=Tree[k].Lazy*(Tree[k<<1].r-Tree[k<<1].l+1);
        Tree[k<<1].Lazy+=Tree[k].Lazy;
        Tree[k<<1|1].sum+=Tree[k].Lazy*(Tree[k<<1|1].r-Tree[k<<1|1].l+1);
        Tree[k<<1|1].Lazy+=Tree[k].Lazy;
        Tree[k].Lazy=0;
    }
}
void update(int k,int L,int R,long long val)
{    
    push_down(k);
    if(L<=Tree[k].l && Tree[k].r<=R)
    {
        Tree[k].sum+=val*(Tree[k].r-Tree[k].l+1);
        Tree[k].Lazy+=val;
        return;
    }
    int mid=Tree[k].l+Tree[k].r>>1;
    if(L<=mid) update(k<<1,L,R,val);
    if(R>mid) update(k<<1|1,L,R,val);
    push_up(k);
}
long long Query(int k,int L,int R)
{
    if(L<=Tree[k].l && Tree[k].r<=R)
    {
        return Tree[k].sum;
    }
    push_down(k);
    long long res=0;
    int mid=Tree[k].l+Tree[k].r>>1;
    if(L<=mid) res+=Query(k<<1,L,R);
    if(R>mid) res+=Query(k<<1|1,L,R);
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    Build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%d%lld",&x,&y,&z);
            update(1,x,y,z);
        }
        else if(opt==2)
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",Query(1,x,y));
        }
    }
    return 0;
}
View Code

 

二.区间乘法和加减修改,区间查询。

  来自洛谷【模板】线段树2……

  在这种情况下要注意优先处理加标记,按先乘后加运算……

#include<bits/stdc++.h>
using namespace std;
struct SegTree
{
    int l,r;
    long long sum,Add,Mul;
}Tree[1000040];
int n,m,p,x,y,z,opt,a[100010];
void push_up(int k)
{
    Tree[k].sum=(Tree[k<<1].sum+Tree[k<<1|1].sum)%p;
}
void Build(int k,int l,int r)
{
    Tree[k].Add=0;
    Tree[k].Mul=1;
    Tree[k].l=l;
    Tree[k].r=r;
    if(l==r)
    {
        Tree[k].sum=a[l]%p;
        return;
    }
    int mid=l+r>>1;
    Build(k<<1,l,mid);
    Build(k<<1|1,mid+1,r);
    push_up(k);
}
void push_down(int k)
{
    Tree[k<<1].Add=(Tree[k].Add+Tree[k<<1].Add*Tree[k].Mul)%p;
    Tree[k<<1|1].Add=(Tree[k].Add+Tree[k<<1|1].Add*Tree[k].Mul)%p;
    Tree[k<<1].Mul=(Tree[k<<1].Mul*Tree[k].Mul)%p;
    Tree[k<<1|1].Mul=(Tree[k<<1|1].Mul*Tree[k].Mul)%p;
    Tree[k<<1].sum=(Tree[k<<1].sum*Tree[k].Mul+Tree[k].Add*(Tree[k<<1].r-Tree[k<<1].l+1))%p;
    Tree[k<<1|1].sum=(Tree[k<<1|1].sum*Tree[k].Mul+Tree[k].Add*(Tree[k<<1|1].r-Tree[k<<1|1].l+1))%p;
    Tree[k].Add=0;
    Tree[k].Mul=1;
}
void update_Add(int k,int L,int R,long long val)
{    
    push_down(k);
    if(L<=Tree[k].l && Tree[k].r<=R)
    {
        Tree[k].Add=(Tree[k].Add+val)%p;
        Tree[k].sum=(Tree[k].sum+Tree[k].Add*(Tree[k].r-Tree[k].l+1))%p;
        return;
    }
    int mid=Tree[k].l+Tree[k].r>>1;
    if(L<=mid) update_Add(k<<1,L,R,val);
    if(R>mid) update_Add(k<<1|1,L,R,val);
    push_up(k);
}
void update_Mul(int k,int L,int R,long long val)
{    
    push_down(k);
    if(L<=Tree[k].l && Tree[k].r<=R)
    {
        Tree[k].Mul=(Tree[k].Mul*val)%p;
        Tree[k].Add=(Tree[k].Add*val)%p;
        Tree[k].sum=(Tree[k].sum*Tree[k].Mul)%p;
        return;
    }
    int mid=Tree[k].l+Tree[k].r>>1;
    if(L<=mid) update_Mul(k<<1,L,R,val);
    if(R>mid) update_Mul(k<<1|1,L,R,val);
    push_up(k);
}
long long Query(int k,int L,int R)
{
    if(L<=Tree[k].l && Tree[k].r<=R)
    {
        return Tree[k].sum%p;
    }
    push_down(k);
    long long res=0;
    int mid=Tree[k].l+Tree[k].r>>1;
    if(L<=mid) res+=Query(k<<1,L,R);
    if(R>mid) res+=Query(k<<1|1,L,R);
    return res%p;
}
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    Build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%d%lld",&x,&y,&z);
            update_Mul(1,x,y,z);
        }
        else if(opt==2)
        {
            scanf("%d%d%lld",&x,&y,&z);
            update_Add(1,x,y,z);
        }
        else if(opt==3)
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",Query(1,x,y));
        }
    }
    return 0;
}
View Code

 

其他的等待补充 扫描线算法我会过后写学习笔记~

大家也可以评论一些线段树的应用~我会补充的~

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!