蓝书(算法竞赛进阶指南)刷题记录——POJ3468 A Simple Problem with Intergers(树状数组维护差分)

题目:POJ3468.
题目大意:给定一个长度为 n n n的序列 a a a,要求支持:
1.格式 C   a   b   c C\,a\,b\,c Cabc,表示将 [ a , b ] [a,b] [a,b]的权值都加上 c c c.
2.格式 Q   a   b Q\,a\,b Qab,表示查询 [ a , b ] [a,b] [a,b]的权值和.
设操作数为 m m m,那么 1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1n,m105.

线段树裸题,可是我们这里不用线段树,我们讨论树状数组的解法.

我们已经知道树状数组支持单点修改区间查询和区间修改单点查询,那么可不可以让树状数组支持区间修改区间查询呢?

我们现在继续将思路留在差分数组上,我们设 A A A a a a的差分数组,那么 A [ 1 , n ] A[1,n] A[1,n]的和就是:
∑ i = 1 n ∑ j = 1 i A [ j ] = ∑ i = 1 n A [ i ] ∗ ( n − i + 1 ) . \sum_{i=1}^{n}\sum_{j=1}^{i}A[j]=\sum_{i=1}^{n}A[i]*(n-i+1). i=1nj=1iA[j]=i=1nA[i](ni+1).

我们发现这个东西用一个树状数组还是不好维护,我们可以再变式:
∑ i = 1 n A [ i ] ∗ ( n − i + 1 ) = ∑ i = 1 n A [ i ] ∗ n − ∑ i = 1 n A [ i ] ∗ ( i − 1 ) . \sum_{i=1}^{n}A[i]*(n-i+1)=\sum_{i=1}^{n}A[i]*n-\sum_{i=1}^{n}A[i]*(i-1). i=1nA[i](ni+1)=i=1nA[i]ni=1nA[i](i1).

我们发现这个东西貌似就可以用两个树状数组维护,我们可以用一个树状数组维护 A [ i ] A[i] A[i],再用一个树状数组维护 A [ i ] ( i − 1 ) A[i](i-1) A[i](i1).

代码如下:

//#include<bits/stdc++.h>
#include<iostream>
  using namespace std;
#define Abigail inline void
typedef long long LL; 
const int N=100000;
LL c[N+9][2],a[N+9];
int n,q;
int lowbit(int x){return x&-x;}
void add(int x,LL num,int t){
  while (x<=n){
    c[x][t]+=num;
    x+=lowbit(x);
  }
}
LL query(int x,int t){
  LL sum=0;
  while (x){
    sum+=c[x][t];
    x-=lowbit(x);
  }
  return sum;
}
char rc(){
  char c=getchar();
  while (c<'A'||c>'Z') c=getchar();
  return c;
}
Abigail into(){
  scanf("%d%d",&n,&q);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
Abigail work(){
  for (int i=n;i>=1;i--)
    a[i]-=a[i-1];
  for (int i=1;i<=n;i++)
    add(i,a[i],0),add(i,a[i]*(i-1),1);
}
Abigail getans(){
  char opt;
  int l,r;
  LL d;
  for (int i=1;i<=q;i++){
    opt=rc();
    if (opt=='C'){
      scanf("%d%d%lld",&l,&r,&d);
      add(l,d,0);add(r+1,-d,0);
      add(l,d*(l-1),1);add(r+1,-d*r,1);
    }else{
      scanf("%d%d",&l,&r);
      printf("%lld\n",query(r,0)*r-query(r,1)-query(l-1,0)*(l-1)+query(l-1,1));
    }
  }
}
int main(){
  into();
  work();
  getans();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值