由树状数组的知识引申来的
什么是树组呢 我也不说了 根据lowbit写出来的一个关系如图
有时候在对[l,r]一个区间操作的时候很容易t
例如对[l,r]区间都加上k ,如果for循环跑一边 复杂度有点高
现在的话我们引入差分数组
1.定义:
对于已知有n个元素的数列d,我们可以建立记录它每项与前一项差值的差分数组f:显然,f[1]=d[1]-0=d[1];对于整数i∈[2,n],我们让f[i]=d[i]-d[i-1]。
2.简单性质:
计算数列各项的值:观察d[2]=f[1]+f[2]=d[1]+d[2]-d[1]=d[2]可知,数列第i项的值是可以用差分数组的前i项的和计算的,即d[i]=f[i]的前缀和。
3.用途:
(1)快速处理区间加减操作:
假如现在对数列中区间[L,R]上的数加上x,我们通过性质(1)知道,第一个受影响的差分数组中的元素为f[L],即令f[L]+=x,那么后面数列元素在计算过程中都会加上x;最后一个受影响的差分数组中的元素为f[R],所以令f[R+1]-=x,即可保证不会影响到R以后数列元素的计算。这样我们不必对区间内每一个数进行处理,只需处理两个差分后的数即可;
(2)询问区间和问题:
由性质我们可以计算出数列各项的前缀和数组sum各项的值;那么显然,区间[L,R]的和即为ans=sum[R]-sum[L-1];
c数组时a数组的差分数组
a[1]+a[2]+…+a[n]
= (c[1]) + (c[1]+c[2]) + … + (c[1]+c[2]+…+c[n])
= n*c[1] + (n-1)*c[2] +… +c[n]
= n * (c[1]+c[2]+…+c[n]) - (0c[1]+1c[2]+…+(n-1)*c[n])
所以我们在add的时间 存两个数组 一个维护 c[i] 一个维护 (i-1)*c[i]
然后在进行区间修改的时间 根据之前的关系
add(c1,l,h);add(c1,r+1,-h); //c1维护c[i] 修改的时候没什么
add(c2,l,h*(l-1));add(c2,r+1,-h*r);//c2维护(i-1)*c[i] 修改的时间注意(i-1) 与之前保持一致
- 最后进行sum求和的时间 对于第一个c1 要*所对应的倍数
然后与第二个作差就可以
#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062
typedef long long ll;
typedef pair<int,int> PII;ll mod=1e9+7;
inline int read() {char ch = getchar(); int x = 0, f = 1;while(ch < '0' || ch > '9') {if(ch == '-') f = -1;ch = getchar();} while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();} return x * f;}
int qow_m(int n,int w){int k=1;while(w){if(w&1)k=k*n%mod; n=n*n%mod; w>>=1;}return k%mod; }
//ll read(){ll res = 0, ch, flag = 0;if((ch = getchar()) == '-')flag = 1;else if(ch >= '0' && ch <= '9')res = ch - '0';while((ch = getchar()) >= '0' && ch <= '9' )res = res * 10 + ch - '0';return flag ? -res : res;}
const int maxn =1e6+7 ;//..ll sum=1;
ll lowbit(ll x) {return x&(-x);}
ll n,m,k,wz,cnt=0,h,num=0;
ll x,y=0;
ll c2[maxn];
ll c1[maxn];
void add(ll *t,ll x,ll w)
{
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=w;
}
ll sum(ll *t,ll x)
{
ll s=0;
for(int i=x;i>=1;i-=lowbit(i))
s+=t[i];
return s;
}
int main()
{
cin>>n>>m;
ll od=0;
for(ll i=1;i<=n;i++)
{
ll xz;
xz=read();
add(c1,i,xz-od);
add(c2,i,(i-1)*(xz-od));
od = xz;
}
while(m--)
{
k =read();
if(k==1)
{
ll l,r,h;
l=read();r=read();h=read();
if(l>r)
swap(l,r);
add(c1,l,h);add(c1,r+1,-h);
add(c2,l,h*(l-1));add(c2,r+1,-h*r);
}
if(k==2)
{
ll l,r;
ll sum1,sum2;
l=read();r=read();
if(l>r)
swap(l,r);
sum1=(l-1)*sum(c1,l-1)-sum(c2,l-1);
sum2=r*sum(c1,r)-sum(c2,r);
printf("%lld\n",sum2-sum1);
}
}
return 0;
}