树状数组

树状数组实际上是个数组,维护一个区间,支持查询区间的前缀和,以及修改单点的值。

定义lowbit(x)=x&(-x),表示将x的二进制数只保留从右往左数的第一个1后的数字。

设树状数组为C,规定C[i]维护区间[i-lowbit(i)+1,i]的数字和。因此,要访问C[i]维护的区间的前一个区间,则访问C[i-lowbit(i)];要访问包含C[i]维护的区间的区间,则访问C[i+lowbit(i)](规律)。

因此,区间查询某前缀[1,i],则不断查询C[i]再查询C[i]前一个区间C[i-lowbit(i)]。要单点修改,则不断更改C[i]和包含它的C[i+lowbit(i)]。

 

luogu3374 【模板】树状数组1

题目大意:已知一个数列,你需要进行下面两种操作:1.将某一个数加上x;2.求出某区间每一个数的和。

1操作就是规定动作;2操作输出r前缀和减去l-1前缀和。

#include <cstdio>
#include <cassert>
using namespace std;

const int MAX_N = 500010;
int C[MAX_N], A[MAX_N];
int N;

int Lowbit(int x)
{
    return x&(-x);
}

int Sum(int p)
{
    int ans = 0;
    while (p)
    {
        ans += C[p];
        p -= Lowbit(p);
    }
    return ans;
}

void Modify(int p, int delta)
{
    while (p <= N)
    {
        C[p] += delta;
        p += Lowbit(p);
    }
}

void Init()
{
    for (int i = 1; i <= N; i++)
        Modify(i, A[i]);
}

int main()
{
#ifdef _DEBUG
    freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
    int m, op, p, delta, l, r;
    scanf("%d%d", &N, &m);
    for (int i = 1; i <= N; i++)
        scanf("%d", i + A);
    Init();
    while (m--)
    {
        scanf("%d", &op);
        switch (op)
        {
        case 1:
            scanf("%d%d", &p, &delta);
            Modify(p, delta);
            break;
        case 2:
            scanf("%d%d", &l, &r);
            printf("%d\n", Sum(r) - Sum(l - 1));
            break;
        default:
            assert(0);
        }
    }
    return 0;
}

 

luogu3368 【模板】树状数组2

题目大意:已知一个数列,你需要进行下面两种操作:1.将某区间每一个数数加上x;2.求出某一个数的和。

先不考虑树状数组的问题。设原序列为A,令B[i]=A[i]-A[i-1]。查询点,相当于A[i]=sum (foreach j=1 to i)B[i]。更改一个区间[i,j],就相当于B[i]+1,B[j+1]-1。用树状数组C维护B,就可满足树状数组“单点修改,区间查询”的操作了。

#include <cstdio>
#include <cstring>
#include <cassert>
using namespace std;

const int MAX_N = 500010;
int A[MAX_N], B[MAX_N], C[MAX_N];
int N;

int Lowbit(int x)
{
    return x&(-x);
}

int Sum(int p)
{
    int sum = 0;
    while (p)
    {
        sum += C[p];
        p -= Lowbit(p);
    }
    return sum;
}

void Update(int p, int delta)
{
    while (p <= N)
    {
        C[p] += delta;
        p += Lowbit(p);
    }
}

int main()
{
#ifdef _DEBUG
    freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
    int opCnt, op, l, r, k, x;
    scanf("%d%d", &N, &opCnt);
    for (int i = 1; i <= N; i++)
    {
        scanf("%d", i + A);
        B[i] = A[i] - A[i - 1];
        Update(i, B[i]);
    }
    while (opCnt--)
    {
        scanf("%d", &op);
        switch (op)
        {
        case 1:
            scanf("%d%d%d", &l, &r, &k);
            Update(l, k);
            Update(r + 1, -k);
            break;
        case 2:
            scanf("%d", &x);
            printf("%d\n", Sum(x));
            break;
        }
    }
    return 0;
}

 

posted @ 2018-02-13 08:49  headboy2002  阅读(117)  评论(0编辑  收藏  举报