做这道题让我对线段树和树状数组有了更深的理解。。
主要是维护两个前缀和,一个a[i],一个(n-i+1)*a[i],最后结果减一下。剩下就是注意一些树状数组的操作更改了。
附上通过代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define ll long long
const int MAX=112345;
ll aa[MAX],s1[MAX],s2[MAX];
ll t1[MAX],t2[MAX];
ll n,q,ans;
ll lowbit(ll i)
{
return i&(-i);
}
void update1(ll i,ll k)
{
while(i<=n)
{
t1[i]+=k;
i+=lowbit(i);
}
}
ll query1(ll i)
{
ll sum=0;
while(i>0)
{
sum+=t1[i];
i-=lowbit(i);
}
return sum;
}
void update2(ll i,ll k)
{
while(i<=n)
{
t2[i]+=k;
i+=lowbit(i);
}
}
ll query2(ll i)
{
ll sum=0;
while(i>0)
{
sum+=t2[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
while(scanf("%lld%lld",&n,&q)==2)
{
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
memset(aa,0,sizeof(aa));
for(int i=1;i<=n;i++)
{
scanf("%lld",&aa[i]);
s1[i]=s1[i-1]+aa[i];
s2[i]=(n-i+1)*aa[i]+s2[i-1];
}
/*for(int i=1;i<=n;i++)
cout<<s1[i]<<" "<<s2[i]<<endl;*/
for(int i=1;i<=n;i++)
{
update1(i,aa[i]);
update2(i,(n-i+1)*aa[i]);
}
int c;ll a,b;
for(int i=1;i<=q;i++)
{
scanf("%d%lld%lld",&c,&a,&b);
if(c==1)
{
ll k1=query1(b)-query1(a-1);
ll k2=query2(b)-query2(a-1);
ll t=n-b;
//cout<<"k2="<<k2<<" k1="<<k1<<" t="<<t<<endl;
ans=k2-t*k1;
printf("%lld\n",ans);
}
else
{
update1(a,b-aa[a]);
update2(a,(n-a+1)*(b-aa[a]));
aa[a]=b;//注意不能忘!(因为可能重复更新一个位置的值)
}
}
}
return 0;
}