首页 > 编程语言 > 详细

树状数组的区间修改与区间查修

时间:2018-05-15 10:19:52      阅读:141      评论:0      收藏:0      [点我收藏+]

考虑差分
sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i-1)+delta[3]*(i-2)+...+delta[i]*1 // a[i]为原始数组
= sigma(a[x])+sigma(delta[x]*(i+1-x))
= sigma(a[x])+(i+1)*sigma(delta[x])-sigma(delta[x]*x)
所以我们记sum为前缀和,delta[i],deltai[i]=delta[i]*i

//sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i - 1) + delta[3]*(i - 2)+...+delta[i]*1   // a[i]为原始数组  
    //= sigma( a[x] ) + sigma( delta[x]  *  (i + 1 - x) )  
    //= sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )  
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
int n;
long long sum[N];//原始数组前缀和 
long long delta[N];//差分数组 
long long deltai[N];//delta[x]*i 
inline int lowbit(int x) {return x&(-x);}
void add(long long *c,int a,int b)
{
    while(a<=n)
    {
        c[a]+=b;
        a+=lowbit(a);
    }
}
long long query(long long *c,int a)
{
    long long s=0;
    while(a) 
    {
        s+=c[a];
        a-=lowbit(a);
    }
    return s;
}

int main()
{
    freopen("a.in","r",stdin);
    scanf("%d",&n);
    int a;
    for(int i=1;i<=n;i++) scanf("%d",&a),sum[i]=sum[i-1]+a;
    int m,l,r,x;
    scanf("%d",&m);
    long long suml,sumr;
    for(int i=1;i<=m;i++) 
    {
        scanf("%d",&a);
        if(a==1)
        {
            scanf("%d%d%d",&l,&r,&x);
            add(delta,l,x);add(delta,r+1,-x);
            add(deltai,l,x*l);add(deltai,r+1,-x*(r+1));
        }
        else 
        {
            scanf("%d%d",&l,&r);
            suml=sum[l-1]+l*query(delta,l-1)-query(deltai,l-1);
            sumr=sum[r]+(r+1)*query(delta,r)-query(deltai,r);
            printf("%lld\n",sumr-suml);
        }
    }
    
    return 0;
}

 

树状数组的区间修改与区间查修

原文:https://www.cnblogs.com/Heey/p/9039113.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!