[bzoj3155][树状数组]Preprefix sum

Description

这里写图片描述

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

HINT

1<=N,M<=100000,且在任意时刻0<=Ai<=100000

题解

随便推一下
其实就是要维护一个Sigma(a[i]*(n-i+1))的前缀和
那么这个前缀和这样是维护不了的
换一种思维,把里面拆开来
相当于Sigma(a[i]* n)-Sigma(a[i]* (i-1))
第一个维护一下a[i]的前缀和,第二个维护一下a[i]*(i-1)的前缀和
输出的时候把第一个前缀和集体乘一个输入的i,再减去第二个前缀和即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL s[110000][2];int n,m;
int lowbit(int x){return x&-x;}
void change(int x,LL c,int op)
{
    while(x<=n)
    {
        s[x][op]+=c;
        x+=lowbit(x);
    }
}
LL findsum(int x,int op)
{
    LL ret=0;
    while(x>=1)
    {
        ret+=s[x][op];
        x-=lowbit(x);
    }
    return ret;
}
char ss[10];
LL col[110000];
int main()
{
    scanf("%d%d",&n,&m);    
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&col[i]);
        change(i,col[i],0);
        change(i,(i-1)*col[i],1);
    }
    while(m--)
    {
        int u;LL v;
        scanf("%s%d",ss+1,&u);
        if(ss[1]=='Q')printf("%lld\n",findsum(u,0)*u-findsum(u,1));
        else
        {
            scanf("%lld",&v);
            change(u,v-col[u],0);
            change(u,(u-1)*(v-col[u]),1);
            col[u]=v;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值