1. 程式人生 > >ACM-ICPC 2018 徐州賽區網路預賽 H. Ryuji doesn't want to study(線段樹區間求和)

ACM-ICPC 2018 徐州賽區網路預賽 H. Ryuji doesn't want to study(線段樹區間求和)

樣例輸入 
5 3
1 2 3 4 5
1 1 3
2 5 0
1 4 5
樣例輸出 
10
8

題意:n長的數列,q個詢問,1操作表示輸出l到r (r-l+1)*a[l]+(r-l)*a[l-1]+……+a[r]的和 ,2表示將a[l]更新為r

思路:線段樹原陣列為a的字首和陣列,那麼a[l]更新為r只需要在[l,n]區間,都加上(r-更新前的值)就好了,要更新原陣列a[l]=r,因為一個點可能會重複更新。求和,可以發現,需要求的答案=字首和區間[l,r]的和,減去(r-l+1)*presum[l-1],而這個減去的部分也需要用區間求和來得到,而不能直接用presum[l-1],因為會有延遲更新的存在。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100005
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
ll tree[maxn<<2],add[maxn<<2];
ll a[maxn],presum[maxn];
int n,q;
void build(int rt,int l,int r){
    add[rt]=0;
    if(l==r){
        tree[rt]=presum[l];
    } else {
        int m=l+r>>1;
        build(rt<<1,l,m);
        build(rt<<1|1,m+1,r);
        tree[rt]=tree[lson]+tree[rson];
    }
}

void PushDown(int rt,int l,int r){
    int m=(l+r)/2;
    tree[lson]+=add[rt]*(m-l+1);
     add[lson]+=add[rt];
    tree[rson]+=add[rt]*(r-(m+1)+1);
     add[rson]+=add[rt];
    add[rt]=0;
}

ll query(int rt,int l,int r,int L,int R)
{
    if(r<L||R<l)return 0;
    else if(L<=l&&r<=R)return tree[rt];
    PushDown(rt,l,r);
    int m=l+r>>1;
    return query(lson,l,m,L,R)+query(rson,m+1,r,L,R);
}

void update(int rt,int l,int r,ll v,int L,int R)
{
    if(r<L||R<l)return ;
    else if(L<=l&&r<=R){
        add[rt]+=v;
        tree[rt]+=v*(r-l+1);
        return ;
    }
    PushDown(rt,l,r);
    int m=l+r>>1;
    update(lson,l,m,v,L,R);
    update(rson,m+1,r,v,L,R);
    tree[rt]=tree[lson]+tree[rson];
}

int main(){
    scanf("%d%d",&n,&q);
    presum[0]=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        presum[i]=presum[i-1]+a[i];
    }
    build(1,1,n);
    while(q--){
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1){
            ll ans=query(1,1,n,l,r);
            if(l!=1)ans-=(r-l+1)*query(1,1,n,l-1,l-1);
            printf("%lld\n",ans);

        }
		else{
            update(1,1,n,r-a[l],l,n);
            a[l]=r;
        }
    }
    return 0;
}