AcWing 243. 一个简单的整数问题2(树状数组区间修改 区间查询)

本文讲解如何利用树状数组优化区间修改和查询操作,通过构造c1和c2数组维护i*b[i]的前缀和,简化计算区间和的过程,并揭示了公式推导的关键思想。适用于处理动态更新的复杂问题,时间复杂度为O(mlogn)。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

题意

微信图片_20220213170312.png
本题要求运用树状数组实现 区间修改区间查询

思路

上一题 中,我们用树状数组维护了一个原数组a的差分数组b,对于每一条指令“C l r d”,把b[i]加上d, 再把b[r+1]减去d

已经讨论得知的是:b1~x前缀和b[1~x]就是经过这些指令后,a[x]增加的值。

那么a序列的前缀和a[1~x]整体增加的值就是微信图片_20220213170853.png

上式可以经过推导进一步改写为:

微信图片_20220213171010.png
以上公式即用于求解区间[1, x]的所有元素和

推导过程:

微信图片_20220213171348.png

因此在这道题中我们可以考虑增加一个树状数组,用于维护i*b[i]的前缀和微信图片_20220213171544.png ,上面的式子就可以直接进行计算了。

具体地说,我们建立两个树状数组,分别为c1, c2,起初全赋值为0,对于每一条指令“C l r d”,执行四个操作:

  • c1l位置加上d
  • c1r+1位置减去d
  • c2l位置加上l*d
  • c2r+1位置减去(r+1)*d

对于每一条指令“Q l r”,我们直接套取上面推出来的式子进行代入计算即可。

这道题带给我们一种思想,分离包含有多个变量的项,使公式中不同变量之间互相独立,这种思想很重要。

时间复杂度

O(mlogn)

代码

#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1e5+10;
int n, m;
int a[N], c1[N], c2[N];

int read() {//快读
    int x=0,f=1; char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}

inline int lowbit(int x) {return x & (-x);}

int ask(int c[], int x)
{
        int ans = 0;
        while(x) {ans+=c[x], x-=lowbit(x);}
        return ans;
}

int add(int x, int y, int c[])
{
        for(; x<=n; x+=lowbit(x)) c[x]+=y;
}

signed main()
{
        cin>>n>>m;
        for(int i=1;i<=n;++i)
        {
                a[i] = read();
                add(i, a[i]-a[i-1], c1), add(i, i*(a[i]-a[i-1]), c2);
        }
        while(m--)
        {
                char op[2];
                int l, r, d;
                scanf("%s", op);
                l = read(), r = read();
                if(*op=='C')
                {
                        d = read();
                        add(l, d, c1), add(l, l*d, c2);
                        add(r+1, -d, c1), add(r+1, -(r+1)*d, c2);
                }
                else
                {
                        printf("%lld\n", (r+1)*(ask(c1, r)) - ask(c2, r) - l*(ask(c1, l-1)) + ask(c2, l-1));
                }
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值