一个简单的整数问题2(树状数组实现区间修改+区间查询)

题目

题目传送门
给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 数列中第 l~r 个数的和。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行表示M条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。

样例输入

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

样例输出

4
55
9
15

题解

∑ i = 1 x b [ i ] \sum\limits_{i=1}^{x}b{[i]} i=1xb[i]就是 a [ i ] a[i] a[i]增加的值
那么 a [ 1 ∼ x ] a[1 \sim x] a[1x]整体增加的值就是
∑ i = 1 x ∑ j = 1 i b [ j ] \sum\limits_{i=1}^{x}\sum\limits_{j=1}^{i}b[j] i=1xj=1ib[j]
上式可以改写为
∑ i = 1 x ∑ j = 1 i b [ j ] = ∑ i = 1 x ( x − i + 1 ) ∗ b [ i ] = ( x + 1 ) ∑ i = 1 x b [ i ] − ∑ i x i ∗ b [ i ] \sum\limits_{i=1}^{x}\sum\limits_{j=1}^{i}b[j] =\sum\limits_{i=1}^{x}(x-i+1)*b[i]=(x+1)\sum\limits_{i=1}^{x}b[i]-\sum\limits_{i}^{x}i*b[i] i=1xj=1ib[j]=i=1x(xi+1)b[i]=(x+1)i=1xb[i]ixib[i]

对于每条指令"C l r d" 执行四个操作:

  1. c 0 c_0 c0中把 l l l的位置上的数字加上 d d d
  2. c 0 c_0 c0中把 r + 1 r+1 r+1的位置上的数字加上 − d -d d
  3. c 1 c_1 c1中把 l l l的位置上的数字加上 l ∗ d l*d ld
  4. c 1 c_1 c1中把 r + 1 r+1 r+1的位置上的数字加上 − ( r + 1 ) ∗ d -(r+1)*d (r+1)d

对于每条指令"Q l r" 答案为
( s u m [ r ] + ( r + 1 ) ∗ a s k ( c 0 , r ) − a s k ( c 1 , r ) ) − s u m ( [ l − 1 ] + l ∗ a s k ( c 0 , l − 1 ) − a s k ( c 1 , l − 1 ) ) (sum[r]+(r+1)*ask(c_0,r)-ask(c_1,r)) - sum([l-1]+l*ask(c_0,l-1)-ask(c_1,l-1)) (sum[r]+(r+1)ask(c0,r)ask(c1,r))sum([l1]+lask(c0,l1)ask(c1,l1))

code

#include <bits/stdc++.h>
using namespace std; 
const int maxn = 1e5 + 100; 
typedef long long LL; 

template <typename T>
inline void read(T &s) {
    s = 0; 
    T w = 1, ch = getchar(); 
    while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
    while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
    s *= w; 
}

int n, m; 
int a[maxn];
LL c[2][maxn], sum[maxn]; 

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

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

inline LL ask(int k, int x) {
    LL ans = 0ll; 
    for (; x; x -= lowbit(x)) 
        ans += c[k][x]; 
    
    return ans; 
}

int main() {
    read(n), read(m); 
    for (int i = 1; i <= n; ++i) {
        read(a[i]); 
        sum[i] = sum[i - 1] + a[i]; 
    }
    
    while (m--) {
        char ch; cin >> ch;  
        
        if (ch == 'C') {
            int l, r, d; 
            read(l), read(r), read(d); 
            
            add(0, l, d); 
            add(0, r + 1, -d); 
            add(1, l, l * d); 
            add(1, r + 1, -(r + 1) * d); 
        }
        else if (ch == 'Q') {
            int l, r; 
            read(l), read(r); 
            
            LL ans = sum[r] + (r + 1) * ask(0, r) - ask(1, r); 
            // check; 
            ans -= sum[l - 1] + l * ask(0, l - 1) - ask(1, l - 1);  
            
            printf("%lld\n", ans); 
        }
    }
    return 0; 
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值