前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进阶版树状数组

进阶版树状数组

作者头像
glm233
发布2020-09-28 10:30:25
3650
发布2020-09-28 10:30:25
举报
文章被收录于专栏:glm的全栈学习之路

我们都知道树状数组一般有两种形式

1.最为传统的版本,支持区间求和,单点修改

2.差分树状数组 支持区间修改,单点查询

而进阶版树状数组 可支持 区间求和,区间修改

其原理是:

设tree[i]=a[i]-a[i-1](差分),那么容易得到:

tree[1]+tree[2]+……+tree[i]=a[i]这个公式

维护tree数组即可以实现区间修改了。

接下来是区间查询的实现问题

我们已经推出了一个公式:

代码语言:javascript
复制
tree[1]+tree[2]+……tree[i]=a[i]

那么,对于1到r的区间和,即为:

代码语言:javascript
复制
 a[1]+a[2]+……+a[r-1]+a[r]
//用上方公式推导得出
=tree[1]+(tree[1]+tree[2])+……+(tree[1]+……+tree[r])
//根据加法交换律与结合律:
=(tree[1]*(r))+(tree[2]*(r-1))+……(tree[r]*1)
//那么:
=r*(tree[1]+tree[2]+……+tree[r])-(tree[1]*0+tree[2]*1+……+tree[r]*(r-1))

看到这里,是不是已经很清晰了呢?

对于a的树状数组(差分)tree,建立一个新的树状数组tree1使得:

tree1[i]=tree[i]*(i-1)

之后,x到y的区间和即为:

(y*query(tree,y)-(x-1)*query(tree,x-1))-(query(tree1,y)-query(tree1,x-1))

P3372 【模板】线段树 1

这种树状数组可以实现线段树的某些功能

代码语言:javascript
复制
#include<bits/stdc++.h>
#define rg register
#define inf 2147483647
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define maxn 100005
const double eps=1e-8;
using namespace std;
inline ll read()
{
    char ch=getchar();ll s=0,w=1;
    while(ch<48||ch>57){if(ch=='-')w=-1;ch=getchar();}
    while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
    return s*w;
}
inline void write(ll x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
ll n,m;
ll tree[maxn],tree1[maxn];
inline ll lb(ll x)
{
    return x&-x;
}
inline void add(ll *tree,ll x,ll k)
{
    for(;x<=n;x+=lb(x))
    {
        tree[x]+=k;
    }
}
inline ll query(ll *tree,ll x)
{
    ll ans=0;
    for(;x;x-=lb(x))
    {
        ans+=tree[x];
    }
    return ans;
}
int main()
{
    n=read(),m=read();
    ll now,last=0;
    for( rg ll i=1;i<=n;i++)
    {
        now=read();
        add(tree,i,now-last);
        add(tree1,i,(now-last)*(i-1));
        last=now;
    }
    for(rg ll i=1;i<=m;i++)
    {
        ll x;
        x=read();
        if(x==1)
        {
            ll a,b,c;
            a=read(),b=read();c=read();
            add(tree,a,c);
            add(tree,b+1,-c);
            add(tree1,a,c*(a-1));
            add(tree1,b+1,-c*b);
        }
        else if(x==2)
        {
           ll  a,b;
           a=read(),b=read();
           cout<<b*query(tree,b)-(a-1)*query(tree,a-1)-(query(tree1,b)-query(tree1,a-1))<<endl;
        }
    }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/06/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档