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) 编辑 收藏 举报