线段树

Posted eric-walker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。

第一种写法

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define I long long
#define FO(i,a,b) for(R I i=a;i<=b;++i)
#define fo(i,a,b) for(R I i=a;i<b;++i)
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (ls(x)|1)
CT I N =100005;
// CT I M = 200005;
// const I inf = 2747483647/3;
using namespace std;
ll sum[N<<2];
ll bt[N<<2];
ll len[N<<2];
I n,m;
void down(I son){
    bt[ls(son)]+=bt[son];
    bt[rs(son)]+=bt[son];
    sum[ls(son)]+=bt[son]*len[ls(son)];
    sum[rs(son)]+=bt[son]*len[rs(son)];
    bt[son]=0;
}
void insert(I id,I v,I le=1,I re=n,I son=1) {
    if(le==re){
        sum[son]=v;
        len[son]=1;
        return ;
    }
    I mid=(le+re)>>1;
    if (id<=mid) {
        insert(id,v,le,mid,ls(son));
    } else {
        insert(id,v,mid+1,re,rs(son));
    }
    sum[son]=sum[ls(son)]+sum[rs(son)];
    len[son]=len[ls(son)]+len[rs(son)];
}
void add(I l,I r,I k,I le=1,I re=n,I son=1){
    if(l<=le&&re<=r){
      sum[son]+=k*len[son];
      bt[son]+=k;
      return ;
    }
    I mid=(le+re)>>1;
    down(son);
    if(l<=mid){add(l,r,k,le,mid,ls(son));}
    if(r>mid){add(l,r,k,mid+1,re,rs(son));}
    sum[son]=sum[ls(son)]+sum[rs(son)];
}
ll getsum(I l,I r,I le=1,I re=n,I son=1){
    if(l<=le&&re<=r){
        return sum[son];
    }
    down(son);
    I mid=(le+re)>>1;
    ll ans=0;
    if(l<=mid) ans+=getsum(l,r,le,mid,ls(son));
    if(r>mid) ans+=getsum(l,r,mid+1,re,rs(son));
    return ans;
}
int main(){
    scanf("%lld%lld",&n,&m);
    FO(i,1,n){
        I x;
        scanf("%lld",&x);
        insert(i,x);
    }
    FO(i,1,m){
        I x;
        scanf("%lld",&x);
        if (x==1) {
            I l,r,k;
            scanf("%lld%lld%lld",&l,&r,&k);
            add(l,r,k);
        } else {
            I l,r;
            scanf("%lld%lld",&l,&r);
            cout<<getsum(l,r)<<endl;
        }
    }
    return 0;
}

 

第二种写法

 

#include<iostream>
#include<cstdio>
using namespace std;
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
struct FFF{
    int l,r;
    int sum;
    int tag;
    int mid(){return l+r>>1;}
    int len(){return r-l+1;}
}t[100000<<2];
int read();
int n;
void pushup(int o){
    t[o].sum=t[ls(o)].sum+t[rs(o)].sum;
}
void pushdown(int o){
    int & v=t[o].tag;
    t[ls(o)].tag+=v;
    t[rs(o)].tag+=v;
    t[ls(o)].sum+=v*t[ls(o)].len();
    t[rs(o)].sum+=v*t[rs(o)].len();
    v=0;
}
void build(int l=1,int r=n,int o=1){
    t[o].l=l;t[o].r=r;
    if(l==r){
        t[o].sum=read();
        return;
    }
    int mid=t[o].mid;
    build(l,mid,ls(o));
    build(mid+1,r,rs(o));
}
void add(int l,int r,int k,int o=1){
    if(l<=t[o].l&&t[o].r<=r){
        t[o].sum+=k*t[o].len();
        t[o].tag+=k;
        return ;
    }
    int mid=t[o].mid();
    pushdown(o);
    if(l<=mid){add(l,r,k,ls(o));}
    if(r>mid){add(l,r,k,rs(o));}
    pushup(o);
}
int getsum(int l,int r,int o=1){
    if(l<=t[o].l&&t[o].r<=r){
        return t[o].sum;
    }
    pushdown(o);
    int mid=t[o].mid();
    int ans=0;
    if(l<=mid) ans+=getsum(l,r,ls(o));
    if(r>mid) ans+=getsum(l,r,rs(o));
    return ans;
}
int main(){

    return 0;
}

  

 

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树