题目链接:https://nanti.jisuanke.com/t/A2007
题目大意:有一个序列含有n个数a[1],a[2],a[3],……a[n],有两种操作:
第一种操作:k=1,l,r,询问区间[l,r]中a[l]*len+a[l+1]*(len-1)+a[l+2]*(len-2)……+a[r]*1,其中len=(r-l+1),即区间长度
第二种操作:k=2, l,r将下标为l的值a[l]修改为r
一共有q个询问,对于每个询问,如果k==1,输出答案即可。
解题思路:先进行一个小小的推理
询问可以简化为这种形式:
ans=Σ(i=l->r) (r+1-i)*a[i],然后可转化成,ans=Σ(i=l->r) (r+1)*a[i]-Σ(i=l->r) i*a[i]
然后就变成一个很简单的树状数位维护前缀和问题了,即为前缀和a【i】和i*a【i】就好了
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+5; int n,q; ll sum1[maxn],sum2[maxn]; int lowbit(int x){return x&(-x);} void update(ll a[],int x,ll val){ while(x<=maxn){ a[x]+=val; x+=lowbit(x); } } ll ask(ll a[],int x){ ll res=0; while(x){ res+=a[x]; x-=lowbit(x); } return res; } int main(){ cin>>n>>q; for(int i=1;i<=n;i++){ ll val; cin>>val; update(sum1,i,val); update(sum2,i,i*val); } while(q--){ ll k,x,y; cin>>k>>x>>y; if(k==1){ cout<<(y+1)*(ask(sum1,y)-ask(sum1,x-1))-(ask(sum2,y)-ask(sum2,x-1))<<endl; }else{ ll num=ask(sum1,x)-ask(sum1,x-1); update(sum1,x,y-num); num=ask(sum2,x)-ask(sum2,x-1); update(sum2,x,x*y-num); } } return 0; }