LG4868 Preprefix sum 题解

壹、题目大意

给出长度为 n 的序列 a1an,设 Si=j=1iaj,有两种操作

可以给定 ix,使得 ai=x,也可以给定 i,查询 j=1iSj 的值

n100000

贰、思路

这道题查询的是 S,但实际上是 a,而操作一中修改 ai 也会影响到 SiSn 的值,从而影响操作二

因此考虑维护 a

由上文,修改 ai 会影响到 SiSn,所以我们知道操作一实际上就是对 S 区间加

查询 j=1iSj,实际上就是查询 1i 中各个 S 的和

因此操作二实际上就是对 S 区间查询(是特殊的,从 1 开始)

由此,我们可以想到线段树、分块、树状数组等做法

线段树时间复杂度 O(nlog2n),但常数大,代码编写难度大,可以先放弃

分块时间复杂度 O(nn),这道题 n100000 时接近 107 级别,容易被卡,可以暂时搁置

树状数组的话时间复杂度 O(nlog2n),但常数小,代码编写难度小,对于区间查询手到擒来;

因此优先考虑树状数组

对于区间修改我们看到修改的是 in中的 S 的,可以用差分;但差分有些繁琐,而且差分是对于单点查询的,那如何不差分呢?

因此考虑好数据结构,还要再思考一个问题:如何把题目中问的与 a 无关的式子推成与 a 有关的式子

OI中,推导式子是一个常态

遇到这种有累加值的题目,我们可以首先把题目中的原式转化成与输入的 a 有关联的内容:

j=1iSj=j=1i{k=1jak}

然后我们举一些特殊例子来判断:

a11i 的每一个 S 都计算了一遍,一共计算了 i1+1=i

a22i 的每一个 S 都计算了一遍,一共计算了 i2+1=i1

…………

aiii 的每一个 S 都计算了一边,一共计算了 ii+1=1

然后我们可以发现,对于一个 ak,它对 1i 的这么一个查询,如果设它的 贡献 为它为答案贡献的数值,

那它的 贡献 便是它本身的数值乘上它在前缀和里面出现的次数,即 Contribute(k)=akcntk=ak(ik+1)

每个 ak 的贡献之和便是要查询的答案

所以

j=1i{k=1jak}=j=1iContribute(j)=j=1i{aj(ij+1)}

拆开,得到

(i+1)j=1iajj=1i{ajj}

拆到这里,想必大家都明白了,这里有两个前缀和:ajajj

所以我们需要维护两个树状数组,一个里面是 aj ,另一个里面是 ajj

然后按照这个式子写出来即可

(注意树状数组大小范围)

叄、代码

#include<bits/stdc++.h>
#define endl "\n"
#define int long long//要开 long long
using namespace std;
const int N=100009;
int n,m;
int a[N];
class tree_array
{
private:
int s[N<<1];
inline int lowbit(int x){return x&(-x);}
public://模板操作
inline void add(int point,int val)
{
for(int i=point;i<=(n<<1);i+=lowbit(i)) s[i]+=val;
return;
}
inline int query(int point)
{
int res=0;
for(int i=point;i>=1;i-=lowbit(i)) res+=s[i];
return res;
}
}bit1,bit2;
//bit1 维护 aj,bit2 维护 aj*j
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
//freopen("sum.in","r",stdin);
//freopen("sum.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];//输入
for(int i=1;i<=n;i++)
{
bit1.add(i,a[i]);
bit2.add(i,a[i]*i);//建立树状数组
}
while(m--)
{
string str;
int u,x;
cin>>str>>u;
if(str=="Modify")
{
cin>>x;
bit1.add(u,x-a[u]);
bit2.add(u,(x-a[u])*u);//修改一下
a[u]=x;
}
else
{
int res=(u+1)*bit1.query(u)-bit2.query(u);//按照推的式子输出即可
cout<<res<<endl;
}
}
return 0;
}
posted @   DreamerX  阅读(11)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示