ACM-ICPC 2018 徐州赛区网络预赛 HRyuji doesn't want to study 树状数组

题目链接: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;
}
原文地址:https://www.cnblogs.com/zjl192628928/p/10665496.html