一个简单的整数问题2-树状数组

给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示询问 数列中第 l~r 个数的和。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行表示M条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
1≤N,M≤1051≤N,M≤105,

|d|≤10000|d|≤10000,

|A[i]|≤1000000000|A[i]|≤1000000000
输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

输出样例:
4
55
9
15

思路:这次要做的事是在一个区间加一个数,查询的也是一个区间的和
在一个区间加一个数,仍然是利用差分的思想
比如查询前x个数的和需要求出
b1
b1 b2
b1 b2 b3

b1 b2 b3 … bx
如何求这些数的和:先把所有的数补齐,(同时上面也补一行)为
b1 b2 b3 …bx
b1 b2 b3… bx
b1 b2 b3…bx
b1 b2 b3…bx

b1 b2 b3…bx
用下面所有的数减去上面缺少的的数就是需要求得数,下面的数是(x+1)(b数组的和)- (1b1+2b2+…+xbx)
综上所诉,如果相求前x个数的和的话,就需要就(x+1)(b数组的和)- (ibi数组的和)
所以,再加入数的时候,需要同时维护俩个差分数组

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100010;
typedef long long LL;
int n,m;
int a[N];
LL tr1[N];
LL tr2[N];
int lowbit(int x){
 return x&-x;
}
void add(LL tr[],int x,LL c){
 for(int i=x;i<=n;i+=lowbit(i))    tr[i]+=c;
}
LL sum(LL tr[],int x){
 LL res=0;
 for(int i=x;i;i-=lowbit(i))   res+=tr[i];
 return res;
}
LL prefix_sum(int x){
 return sum(tr1,x)*(x+1)-sum(tr2,x);
}
int main(){
 scanf("%d%d",&n,&m);
 for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 for(int i=1;i<=n;i++){
  int b=a[i]-a[i-1];
  add(tr1,i,b);
  add(tr2,i,(LL)i*b);
 }
 while(m--){
  char op[2];
  int l,r,d;
  scanf("%s%d%d",op,&l,&r);
  if(*op=='Q'){
   printf("%lld\n",prefix_sum(r)-prefix_sum(l-1));
  }
  else{
   scanf("%d",&d);
   add(tr1,l,d);
   add(tr1,r+1,-d);
   add(tr2,l,l*d);
   add(tr2,r+1,(r+1)*-d);
  }
 }
 return 0;
}
 
发布了29 篇原创文章 · 获赞 24 · 访问量 3671

猜你喜欢

转载自blog.csdn.net/qq_45772483/article/details/104303594