ACM-ICPC 2018 徐州赛区网络预赛 H Ryuji doesn't want to study (树状数组差分)

https://nanti.jisuanke.com/t/31460

题意

两个操作。1:查询区间[l,r]的和,设长度为L=r-l+1, sum=a[l]*L+a[l+1]*(L-1)+...+a[r]。2:将第a个位置修改为b。

分析

变形一下,sum=a[l]*(r-l+1)+a[l+1]*(r-(l+1)-1)+...+a[r](r-r+1)=(r+1)*a[l]-a[l]*l。因此,可维护两个树状数组计算。至于更新操作,实质就是看变化前后的差值,变大就相当与加上差值,否则就是减。注意用longlong

#include<bits/stdc++.h>
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef long long ll;
ll c1[maxn],c2[maxn];
int a[maxn];
int lb(int x){ return x&-x; }
void add(ll c[],int x,ll d){
    while(x<maxn){
        c[x]+=d;
        x+=lb(x);
    }
}
ll sum(ll c[],int x){
    ll res=0;
    while(x){
        res+=c[x];
        x-=lb(x);
    }
    return res;
}
ll query(int l,int r){
    return (r+1)*(sum(c1,r)-sum(c1,l-1))-(sum(c2,r)-sum(c2,l-1)); 
}
int main(){
    int n,q;
    int op,x,y;
    scanf("%d%d",&n,&q);
     for(int i=1;i<=n;i++) {
        scanf("%d",&x);
        add(c1,i,x);
        add(c2,i,1ll*i*x);
        a[i]=x;
    }
    while(q--){
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            printf("%lld
",query(x,y));
        }else{
            add(c1,x,y-a[x]);
            add(c2,x,1ll*x*(y-a[x]));
            a[x]=y;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9668515.html