差分+树状数组p4868Preprefix sum

Posted -guz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了差分+树状数组p4868Preprefix sum相关的知识,希望对你有一定的参考价值。

Description

前缀和(prefix sum)(S_i=sum_{k=1}^i a_i)

前前缀和(preprefix sum) 则把(S_i)作为原序列再进行前缀和。记再次求得前缀和第i个是(SS_i)

给一个长度n的序列(a_1, a_2, cdots, a_n)有两种操作:

  1. Modify i x:把(a_i)改成(x)
  2. Query i:查询(SS_i)

Input

第一行给出两个整数N,M。分别表示序列长度和操作个数

接下来一行有N个数,即给定的序列a1,a2,....an

接下来M行,每行对应一个操作,格式见题目描述

Output

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

显然,这是差分+树状数组

题目中给定的(a_i)就是我们的差分数组。

不会差分的小伙汁,来这里

安利很好的写树状数组的博客.

然后推一下式子.

如果我们修改差分数组(a_i),显然,(S_i)会变化.

(S_i=S_{i-1}+a_i)

现在变成了

(S_i=S_{i-1}+x)

那么差值就变成了(x-a_i)

那么,我们就(add(i,x-a[i])),不要忘了最后将(a_i)变为(x)

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#define int long long
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m,last,t1[1000008],t2[1000008],a[1000008];
#define lowbit(x) x&-x
inline void add(int pos,int x)
{
    for(R int i=pos;i<=n;i+=lowbit(i))
        t1[i]+=x,t2[i]+=pos*x;
}
inline int query(int pos)
{
    R int res=0;
    for(R int i=pos;i;i-=lowbit(i))
        res+=t1[i]*(pos+1)-t2[i];
    return res;
}
char opt[8];
signed main()
{
    in(n),in(m);
    for(R int i=1,x;i<=n;i++)
    {
        in(a[i]);
        add(i,a[i]);
    }
    for(R int i=1,x,y;i<=m;i++)
    {
        scanf("%s",opt+1);
        if(opt[1]=='Q')
        {
            in(x);
            printf("%lld
",query(x));
        }
        else
        {
            in(x),in(y);
            add(x,y-a[x]);
            a[x]=y;
        }
    }
}

以上是关于差分+树状数组p4868Preprefix sum的主要内容,如果未能解决你的问题,请参考以下文章

3155: Preprefix sum

BZOJ3155: Preprefix sum

P3368模板树状数组 2 - 差分

树状数组差分求前缀和的前缀和

树状数组区间修改and查询和

差分数组