线段树(树状数组进阶)

在这里插入图片描述

1.树状数组 1:

题源在这里哦

题解分析:

        首先每块区间分下去,所需要的答案是一段的,正常算法复杂度会很大,线段树可以将复杂度降低到O(mlongn),以下的AC代码,有部分注释 

 AC代码:

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define inf_max 0x7f7f7f7f
typedef long long ll;
///线段树
int a[2000005],f[2000005];//a用于存节点数据,f用于存1-k的线段和
//建立一棵树
inline void buildtree(int k,int l,int r){
    if(l==r){
        f[k]=a[l];
        return;
    }
    int m=l+((r-l)>>1);
    buildtree(k+k,l,m);
    buildtree(k+k+1,m+1,r);
    f[k]=f[k+k]+f[k+k+1];
}
//add 对x上加一个y,那么1-x下标的f都要加上y
inline void add(int k,int l,int r,int x,int y){
    f[k]+=y;
    if(l==r)return;
    int m=l+((r-l)>>1);
    if(x>m)
        return add(k+k+1,m+1,r,x,y);
    else
        return add(k+k,l,m,x,y);
}
//对x-y区间的数字求和,那么就是在l,r区间找到x,y的和
inline int calc(int k,int l,int r,int x,int y){
    if(l==x&&r==y)
        return f[k];
    int m=l+((r-l)>>1);
    if(x>m)
        return calc(k+k+1,m+1,r,x,y);
    else
        if(y<=m)
            return calc(k+k,l,m,x,y);
        else
            return calc(k+k,l,m,x,m)+ calc(k+k+1,m+1,r,m+1,y);
}
void Solve() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>a[i];
    buildtree(1,1,n);
    for(int i=1;i<=m;++i)
    {
        int t,x,y;
        cin>>t>>x>>y;
        if(t==1)
            add(1,1,n,x,y);
        else
            cout<<calc(1,1,n,x,y)<<endl;
    }
}
signed main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    Solve();

}

2.线段树1

题源在这里哦!!

     这是一个带标记的线段树,v【k】作为标记数组,如果是单点修改的话,所以就是区间修改,每次修改的复杂度都是logn,那么总体时间复杂度就是O(mnlongn)那么必会炸!!所以用标记数组存数区间x-y需要加的数据,到最后return 在p[k]+(y-x+1)*v[k];优化了整体的时间复杂度;当然本题数据大,我们直接开long long;

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define inf 0x3f3f3f3f
#define inf_max 0x7f7f7f7f
typedef long long ll;
///线段树
int a[400005],f[400005],v[400005];

//建树
inline void buildtree(int k,int l,int r){
    v[k]=0;
    if(l==r){
        f[k]=a[l];
        return;
    }
    int m=l+((r-l)>>1);
    buildtree(k+k,l,m);
    buildtree(k+k+1,m+1,r);
    f[k]=f[k+k]+f[k+k+1];
}
//mei ge shu jia shang z(x-y)
inline void insert(int k,int l,int r,int x,int y,  int z){
    if(l==x&&y==r){
        v[k]+=z;
        return ;
    }
    f[k]+=(y-x+1)*z;
    int m=l+((r-l)>>1);
    if(x>m)
        insert(k+k+1,m+1,r,x,y,z);
    else
        if(y<=m)
            insert(k+k,l,m,x,y,z);
        else
            insert(k+k,l,m,x,m,z),
            insert(k+k+1,m+1,r,m+1,y,z);
}
//cacl x-y he
int cacl(int k,int l,int r,int x,int y, int p){
    p+=v[k];
    if(l==x&&y==r)
        return f[k]+(y-x+1)*p;
    int m=l+((r-l)>>1);
    if(x>m)
        return cacl(k+k+1,m+1,r,x,y,p);
    else
        if(y<=m)
            return cacl(k+k,l,m,x,y,p);
        else
            return cacl(k+k,l,m,x,m,p)+ cacl(k+k+1,m+1,r,m+1,y,p);

}
void Solve() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>a[i];
    buildtree(1,1,n);
    for(int i=1;i<=m;++i)
    {
        int t;
        cin>>t;
        if(t==1)
        {
            int x,y;
              int z;
            cin>>x>>y>>z;
            insert(1,1,n,x,y,z);
        }else
        {
            int x,y;
            cin>>x>>y;
            cout<<cacl(1,1,n,x,y,0)<<endl;
        }
    }

}
signed main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    Solve();

}

核心部分:

inline void insert(int k,int l,int r,int x,int y,  int z){
    if(l==x&&y==r){
        v[k]+=z;
        return ;
    }
    f[k]+=(y-x+1)*z;
}
//cacl x-y he
int cacl(int k,int l,int r,int x,int y, int p){
    p+=v[k];
    if(l==x&&y==r)
        return f[k]+(y-x+1)*p;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值