[bzoj 3155] Preprefix sum

ε祈祈猫儿з 提交于 2020-02-15 06:56:50

[bzoj 3155] 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

唉,这题可以维护系数做,也可以直接用线段数搞.这里我用简单的方法,直接搞!我们直接维护sum[i]的值,那么询问pos相当于区间\([1,pos]\)的sum和.修改A[i]也好办,区间修改i~n的sum值就行了,改成加法的操作,就可以上线段树.不过也可以用拆一下SSi来用树状数组维护一下系数.有点麻烦,我不讲了.但是这里我用树状数组代替了线段树执行区间修改和区间查询的操作,至于这个是怎么来的,其实也有点像之前那个维护系数的方法,用差分的思路去做就好了.

#include <cstdio>
#include <cstring>
#include <algorithm>

typedef long long LL;

static const int maxm = 1e5 + 10;

LL tr1[maxm],tr2[maxm],A[maxm],sum[maxm];
char ch[10];
int n,m,pos;

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

void Upt(int k,LL val){
    for(int i = k; i <= n ;i += lowbit(i))
        tr1[i] += val,tr2[i] += 1LL * k * val;
}

LL Query(int k){
    LL ret = 0;
    for(int i = k ; i ;i -= lowbit(i))
        ret += 1LL * (k+1) * tr1[i] - tr2[i];
    return ret;
}

int main(){
    LL x;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n ;i++)
        scanf("%lld",&A[i]),sum[i]=sum[i-1]+A[i];
    
    for(int i = 1;i <= n ;i++)
        Upt(i,sum[i]),Upt(i+1,-sum[i]);
    
    while(m--){
        scanf("%s",ch); 
        if(ch[0]=='M'){
            scanf("%d%lld",&pos,&x);
            Upt(pos,x-A[pos]);Upt(n+1,A[pos]-x);
            A[pos]=x;
        }else{
            scanf("%d",&pos);
            printf("%lld\n",Query(pos));
        }
    }

    return 0;
}

传送门

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!