如何用树状数组维护单点查询,区间修改

题目:luogu3368树状数组2.

题目就是让你维护一个序列的区间加,单点查询.

特别水,数据卡不掉线段树.

不过我相信线段树不会比树状数组好写的.

可是树状数组只能维护单点修改,区间查询啊.

那我们可以把这两个问题转化一下.

通过差分,我们可以将一个数组c表示c[i]=a[i]-a[i-1].

那么我们区间修改就只需要修改两个点就可以了,就转化成了单点修改.

与此同时,我们可以发现,原来的a[i]就等于c[1]+c[2]+...+c[i].

那么我们就可以用树状数组维护区间查询.

好像这就可以转化过来了.

AC代码如下:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<iostream>
  using namespace std;
int a;
int n,m;
class tree{
  public:
  long long c[500001];
  inline void clear(){
    for (int i=0;i<=500000;i++)
      c[i]=0;
  }
  inline int lowbit(int x){
    return x&-x;
  }
  inline void add(int x,long long num,int n){
    while (x<=n){
      c[x]+=num;
      x+=lowbit(x);
    }
  }
  inline long long query(int r){
    long long sum=0;
    while (r){
      sum+=c[r];
      r-=lowbit(r);
    }
    return sum;
  }
};
tree tr;
inline long long read(){
  int x=0;
  long long c;
  bool b=0;
  for (c=getchar();c<'0'||c>'9';c=getchar()) if (c=='-') b=1;
  for (;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+c-'0';
  if (b) return (-x);
  else return x;
}
inline void into(){
  int last=0;
  n=read();m=read();
  tr.clear();
  for (int i=1;i<=n;i++){
    a=read();
    tr.add(i,a-last,n);
    last=a;
  }
}
inline void work(){
  int c,x,y;
  long long k;
  for (int i=1;i<=m;i++){
    c=read();
    if (c==1) {
      x=read();y=read();k=read();
      tr.add(x,k,n);
      tr.add(y+1,-k,n);
    }else {
      x=read();
      printf("%lld\n",tr.query(x));
    }
  }
}
inline void outo(){
}
int main(){
  for (int i=1;i<=1;i++){
    into();
    work();
    outo();
  }
  return 0;
}

猜你喜欢

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