洛谷-4868 Preprefix sum

本文介绍了一种使用线段树数据结构解决前缀和及前前缀和问题的方法,通过实例演示了如何处理序列修改和查询操作,特别适用于大数据集上的高效运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
前缀和(prefix sum)Si=∑k=1iakS_i=\sum_{k=1}^i a_kSi=k=1iak
前前缀和(preprefix sum) 则把SiS_iSi​作为原序列再进行前缀和。记再次求得前缀和第iii个是SSiSS_iSSi
给一个长度n的序列a1,a2,⋯ ,ana_1, a_2, \cdots, a_na1,a2,,an​,有两种操作:
Modify i x:把aia_iai​改成x;
Query i:查询SSiSS_iSSi
输入格式
第一行给出两个整数N,M。分别表示序列长度和操作个数
接下来一行有N个数,即给定的序列a1,a2,....ana1,a2,....ana1,a2,....an
接下来M行,每行对应一个操作,格式见题目描述
输出格式
对于每个询问操作,输出一行,表示所询问的SSiSS_iSSi的值。

输入输出样例
输入 #1
5 3
1 2 3 4 5
Query 5
Modify 3 2
Query 5

输出 #1
35
32

说明/提示
1<=N,M<=100000,且在任意时刻0<=Ai<=100000

解释,我们用线段树维护第一个前缀和。如果是操作Q,则查询1-i的求和,如果是M操作,则修改i-n的值,减去以前的再加上修改的

#include<iostream>
#define ll long long
#define N 100004
using namespace std;
ll tree[8*N]={0};
ll lazy[8*N]={0};
void push(int rt,int l,int r){
    int mid=(l+r)/2;
    tree[2*rt]+=lazy[rt]*(mid-l+1);
    tree[2*rt+1]+=lazy[rt]*(r-mid);
    lazy[2*rt]+=lazy[rt];
    lazy[2*rt+1]+=lazy[rt];
    lazy[rt]=0;
}
void update(int rt,int L,int R,int l,int r,ll v){
    push(rt,L,R);
    if(L>=l&&R<=r){
        tree[rt]+=(R-L+1)*v;
        lazy[rt]+=v;
        return;
    }
    int mid=(L+R)/2;
    if(l<=mid) update(2*rt,L,mid,l,r,v);
    if(r>mid) update(2*rt+1,mid+1,R,l,r,v);
    tree[rt]=tree[2*rt]+tree[2*rt+1];
}
ll query(int rt,int L,int R,int l,int r){
    push(rt,L,R);
    if(l<=L&&R<=r){
        return tree[rt];
    }
    ll sum=0;
    int mid=(L+R)/2;
    if(l<=mid) sum+=query(2*rt,L,mid,l,r);
    if(r>mid) sum+=query(2*rt+1,mid+1,R,l,r);
    return sum;
}
char str[123];
ll c[N]={0};
int main(){
    ios::sync_with_stdio(false);
    int n=0,q=0;
    cin>>n>>q;
    for(ll i=1,sum=0;i<=n;i++){
        cin>>c[i];sum+=c[i];update(1,1,n,i,i,sum);
    }
    ll a=0,b=0;
    while(q--){
        cin>>str;
        if(str[0]=='Q'){
            cin>>a;
            cout<<query(1,1,n,1,a)<<endl;
        }else{
            cin>>a>>b;
            update(1,1,n,a,n,b-c[a]);
            c[a]=b;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值