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

本文介绍了一种利用树状数组优化区间查询的方法,适用于动态修改数组元素并快速计算特定区间的加权和问题。通过两个树状数组分别存储前缀和与权重前缀和,实现高效查询和更新。

题意:给你数组a,有两个操作 1 l r,计算l到r的答案:a[l]×L+a[l+1]×(L1)++a[r1]×2+a[r] (L is the length of [ lr ] that equals to r - l + 1),或者 2 i b:把第i个换成b

思路:用一个树状数组存i的前缀和,再用一个树状数组存(n - i + 1)*a[ i ]的前缀和,这样算出后面那个的区间差减去前一个的区间差的某个倍数就会成为答案。

代码:

#include<queue>
#include<cstring>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 100000 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
ll sum[2][maxn], a[maxn];
ll n;
int lowbit(int x){
    return x&(-x);
}
void update(int x, ll v, int id){
    for(int i = x; i <= n; i += lowbit(i)){
        sum[id][i] += v;
    }
}
ll query(int x, int id){
    ll cnt = 0;
    for(int i = x; i > 0; i -= lowbit(i)){
        cnt += sum[id][i];
    }
    return cnt;
}
int main(){
    ll q;
    while(~scanf("%lld%lld", &n, &q)){
        memset(sum, 0, sizeof(sum));
        for(int i = 1; i <= n; i++){
            scanf("%lld", &a[i]);
            update(i, a[i], 0);
            update(i, a[i] * (n - i + 1), 1);
        }
        while(q--){
            ll u, v, w;
            scanf("%lld%lld%lld", &u, &v, &w);
            if(u == 1){
                printf("%lld\n", query(w, 1) - query(v - 1, 1) - (n - w) * (query(w, 0) - query(v - 1, 0)));
            }
            else{
                update(v, -a[v] + w, 0);
                update(v, (-a[v] + w) * (n - v + 1), 1);
                a[v] = w;
            }
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/KirinSB/p/9643550.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值