树状数组专题 (单点更新、区间求和) + (区间更新、单点查询) + (区间更新、区间求和)(差分思想)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tawn0000/article/details/81738773

                                                                                            树状数组专题

一直感觉树状数组用处比较小而且局限、因为最基本的用法就是单点更新和区间求和、但是线段树也能做,只不过代码长一点,但是仔细的去了解了一下树状数组以后发现有很多很赞的地方值得学习。

树状数组详解入口

1.单点更新、区间求和

for(int x = i; x <= n; x += x&-x) c[x] ++; //a[i]单点更新加一
for(int x = r; x ; x -= x&-x) res += c[x]; //求前缀[0,r]

2.区间更新、单点查询

对于操作C L R d  :在区间L-R上每个值增加d  ,运用差分思想,建立一个初始全为0的b数组,b[L] += d; b[R+1] -= d;

for(int x = L; x <= n; x += x&-x) b[x] += d;
for(int x = R+1; x <= n; x -= x&-x) b[x] -= d;

对于操作Q i   A[i] = a[i] + \sum_{j = 1}^{i} b[j]

int res = a[i];
for(int x = i; x ; x -= x&-x)  res += b[x];

3.区间更新、区间查询

设S[x] 为前缀和,S[x] = \sum_{i = 1}^{x} \sum_{j = 1}^{i} b[j] = (x+1)设S[x]为前缀和 c[x] = x*b[x]; 所以有 s[x] = \sum_{i=1}^{x}\sum_{j=1}^{i}b[j] = (x+1)\sum_{i=1}^{x}b[i] - \sum_{i=1}^{x} i * b[i] = (x+1)\sum_{i=1}^{x}b[i] - \sum_{i=1}^{x} c[i]

对于操作 C L R d   b[L] += d; b[R+1] -= d; c[L] += L*d ; c[R+1] += R*d;

for(int x = L; x <= n; x += x&-x) b[x] += d, c[x] += L*d;
for(int x = R+1; x <= n; x += x&-x) b[x] -= d, c[x] -= (R+1)*d;

对于操作 Q L R

int res = s[r] - s[l-1];
for(int x = R; x ; x -= x&-x) res += (R+1)*b[x]-c[x];
for(int x = L-1; x ; x -= x&-x) res -= L*b[x] - c[x];

例题: POJ 3468 A Simple Problem with Intergers

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+100;
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int,int> P;

#define PI 3.1415926
#define sc(x)  scanf("%d",&x)
#define pf(x)  printf("%d",x)
#define pfn(x) printf("%d\n",x)
#define pfs(x) printf("%d ",x)
#define rep(n) for(int i = 0; i < n; i++)
#define per(n) for(int i = n-1; i >= 0; i--)
#define mem(a,x) memset(a,x,sizeof(a))

int n,q;
LL b[maxn],c[maxn],s[maxn];
int a[maxn];

int main()
{
  sc(n),sc(q);
  mem(s,0LL);
  rep(n) {sc(a[i+1]);s[i+1] = s[i] + a[i+1];}
  mem(b,0LL);
  mem(c,0LL);
  rep(q)
  {
    char key[2];
    int l,r,d;
    scanf("%s%d%d",key,&l,&r);
    if(key[0] == 'C')
    {
      sc(d);
      for(int x = l;x <= n; x += x&-x) {b[x] += d;c[x] += l*d;}
      for(int x = r+1;x <= n; x += x&-x) {b[x] -= d;c[x] -= (r+1)*d;}
    }
    else
    {
      LL res = s[r]-s[l-1];
      //res = sum(r) - sum(l-1)   s[x] = ssb[i] = (x+1)sb[i] - isb[i] = (x+1)sb[i] - sc[i];
      for(int x = r; x ; x -= x&-x)  res += ((r+1)*b[x] - c[x]);
      for(int x = l-1; x ; x -= x&-x) res -= (l*b[x] - c[x]);
      printf("%lld\n",res);
    }
  }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Tawn0000/article/details/81738773
今日推荐