Description

[BZOJ3155] Preprefix sum

Input

第一行给出两个整数N,M。分别表示序列长度和操作个数接下来一行有N个数,即给定的序列a1,a2,....an接下来M行,每行对应一个操作,格式见题目描述

Output

对于每个询问操作,输出一行,表示所询问的SSi的值。

Sample Input

5 3
1 2 3 4 5
Query 5
Modify 3 2
Query 5

Sample Output

35
32

试题分析

题目要求:$$\sum_{i=1}^{n} \sum_{j=1}^{i} a_j$$。
转化一下可以变成:$$n\times \sum_{i=1}^{n} a_i - \sum_{i=1}{n}\sum_{j=i+1}{n} a_i$$
然后这个式子就可以两个树状数组维护了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
 
using namespace std;
#define LL long long
 
inline LL read(){
    LL x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 101000;
 
LL N,M; LL c[2][MAXN+1],a[MAXN+1];
char str[MAXN+1];
 
inline LL lowbit(LL x){return x&(-x);}
inline LL Query(LL t,LL x){
    LL res=0;
    while(x) res+=c[t][x],x-=lowbit(x); return res;
}
inline void Add(LL t,LL x,LL k){
    while(x<=N) c[t][x]+=k,x+=lowbit(x); return ;
}
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    N=read(),M=read();
    for(LL i=1;i<=N;i++) a[i]=read(),Add(0,i,(1-i)*a[i]),Add(1,i,a[i]);
    while(M--){
        scanf("%s",str);
        if(str[0]=='Q'){
            LL n=read();
            printf("%lld\n",1LL*n*Query(1,n)+Query(0,n));
        }
        else{
            LL n=read(),x=read();
            Add(0,n,(1-n)*(x-a[n])); Add(1,n,x-a[n]);
            a[n]=x;
        }
    }
    return 0;
}

相关文章:

  • 2022-02-14
  • 2021-05-16
  • 2021-10-22
  • 2021-12-10
  • 2022-02-06
  • 2021-05-02
  • 2022-02-01
猜你喜欢
  • 2021-11-27
  • 2022-02-03
  • 2021-06-08
  • 2021-04-28
  • 2021-12-13
  • 2021-07-31
相关资源
相似解决方案