洛谷-4868 Preprefix sum

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

输入输出样例
输入 #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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值