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

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83008240

题目:poj3468.

题目大意:给定一个序列a,要求支持:

1.格式C a b c,表示将[a,b]的权值都加上c.

2.格式Q a b,表示查询[a,b]的权值和.

线段树裸题(我像个傻子一样写了个LCT做了一遍),可是我们这里不用线段树,我们讨论树状数组的解法.

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

我们现在继续将思路留在差分数组上,我们设A是a的差分数组,那么A[1,n]的和就是\sum_{i=1}^{n}\sum_{j=1}^{i}A[i]=\sum_{i=1}^{n}A[i]*(n-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).

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

代码如下:

//#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;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83008240