没过样例做法树状数组,悬赏1关注

P3372 【模板】线段树 1

ForMyDream @ 2023-01-15 14:00:11

#include<iostream>
using namespace std;
#define lowbit(x) ((x)&-(x))
#define ll long long 
#define maxn 100010

ll tree1[maxn],tree2[maxn],n,m; 

// 在差分数组[x] 的位置增加 d
// 差分数组在这里没有表示出来,因为差分数组就是用 tree 来维护的,tree 就是差分数组+树状数组
void update1(ll x,ll d){
    // 在差分数组[x] 的位置增加 d
    // 差分数组在这里没有表示出来,因为差分数组就是用 tree 来维护的,tree 就是差分数组+树状数组
    while (x<=maxn){
        tree1[x]+=d; x+=lowbit(x);
    }
}

void update2(ll x,ll d){
    while (x<=maxn){
        tree2[x]+=d; x+=lowbit(x);
    }
}

ll sum1(ll x){
    ll ans=0;
    while (x>0){
        ans+=tree1[x]; x-=lowbit(x);
    }
    return ans;
}

ll sum2(ll x){
    ll ans=0;
    while (x>0){
        ans+=tree2[x]; x-=lowbit(x);
    }
    return ans;
}

int main(){
    ios::sync_with_stdio(false);
    // 不用建立原数组了,可以直接将原数组的值代入 tree 中
    cin>>n>>m;
    ll a,old; // a 用于输入原数组的数据,old 存储原数组的上一个元素,用于构造差分
    for (int i=1;i<=n;i++){
        cin>>a;
        update1(i,a-old); // 构造差分 差分[i]=原[i]-原[i-1] 
        update2(i,(i-1)*(a-old)); // 一开始就把 i-1 乘进去 
        old=a; 
    } 
//  cout<<sum1(3)<<endl;
    while (m--){
        ll q,l,r,d;
        cin>>q;
        if (q==1){
            cin>>l>>r>>d;
            update1(l,d);
            update1(r+1,-d); // 差分数组常规操作
            update2(l,d*(l-1)); // 这里的 i(要修改的地方) 就是 l ,乘上 i-1 也就是 l-1 
            update2(r+1,-d*r); // 同理,乘上 i-1 也就是乘上 r+1-1 -> r 
        }
        else {
            cin>>l>>r;
//          cout<<r*sum1(r)<<' '<<sum2(r)<<' '<<(l-1)*sum1(l-1)<<" "<<sum2(l-1)<<endl;
            cout<<r*sum1(r)-sum2(r)-(l-1)*sum1(l-1)+sum2(l-1)<<endl;
        }
    }
    return 0;
}

|