DestinHistoire

 

BZOJ-3155 Preprefix sum(树状数组)

题目描述

  对于一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\),其前缀和 \(S_i\) 为前 \(i\) 个元素的和,即 \(\displaystyle\sum_{k=1}^{i}a_i\)。而前缀和的前缀和就是把前缀和序列 \(S_1,S_2,\cdots,S_n\) 作为原序列,再求一次前缀和。记再次求得得前缀和序列得第 \(i\) 位为 \(SS_i\)

  现在给定一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\)\(m\) 次操作,有两种操作:

  操作 \(1\)Modify i x,将 \(a_i\) 的值改为 \(x\)

  操作 \(2\)Query i,询问 \(SS_i\) 的值。

  数据范围:\(1\leq n,m\leq 10^5\),且在任意时刻 \(0\leq a_i\leq 10^5\)

分析

\[\begin{aligned}&SS_i\\ =&S_1+S_2+\cdots+S_i\\ =&a_1+a_1+a_2+\cdots+a_1+a_2+\cdots+a_i\\ =&a_1\times i+a_2\times(i-1)+\cdots+a_i\\ =&(a_1+a_2+\cdots+a_i)\times i-(0\times a_1+1\times a_2+2\times a_3+\cdots+(i-1)\times a_i) \end{aligned} \]

  一个树状数组维护 \(S_i\),另一个树状数组维护 \((i-1)\times a_i\) 的前缀和。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m;
long long a[N];
int lowbit(int x)
{
    return x&-x;
}
struct FenwickTree
{
    long long c[N];
     void add(int x,int val)
     {
         while(x<=n)
         {
             c[x]+=val;
             x=x+lowbit(x);
         }
     }
     long long query(int x)
     {
         long long ans=0;
         while(x)
         {
             ans=ans+c[x];
             x=x-lowbit(x);
         }
         return ans;
     }
}A,B;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        A.add(i,a[i]);
        B.add(i,(i-1)*a[i]);
    }
    while(m--)
    {
        char op[2];
        scanf("%s",op);
        if(op[0]=='Q')
        {
            int x;
            scanf("%d",&x);
            printf("%lld\n",x*A.query(x)-B.query(x));
        }
        else
        {
            int x;long long val;
            scanf("%d %lld",&x,&val);
            long long temp=val-a[x];
            a[x]=val;
            A.add(x,temp);
            B.add(x,(x-1)*temp);
        }
    }
    return 0;
}

posted on 2020-12-12 00:05  DestinHistoire  阅读(67)  评论(0编辑  收藏  举报

导航