树状数组的基本用法

树状数组的基本用法和奇技淫巧

树状数组是一种修改查找复杂度都是logN的实用的数据结构,大家应该都会,下面放一张熟的不能再熟的图装装样子

树状数组最基本的操作:单点修改,前缀查询。原理都懂就不赘述了,贴个代码。

void add(int pos,int x)
{
    for(;pos<=N;pos+=lowbit(pos))
        c[pos]+=x;
}
int query(int pos)
{
    int sum=0;
    for(;pos;pos-=lowbit(pos))
        sum+=c[pos];
    return sum;
}    

有一种进阶操作,区间修改,单点查询

这就要用到差分——让一个位置的前缀和等于它的值。所以查单点就就是查前缀和。

那如何修改区间呢, 举个例子   比如我们让 区间4 5 7加上3

原数组         1 4 5 7 10   ->  1 7 8 10 10

差分数组     1 3 1 2 3     ->  1  6 1  2  0

显而易见,整个区间加上一个数, 区间内部元素的差是不变的。

在差分数组中,只有这个区间两头的数字改变了 (挺好理解的吧)

于是 ,  就可以通过单点修改区间的两端来进行区间修改了。

代码的话 基本操作和上面是一样的,只是意义不同了 , 唯一不一样的是读入的时候存的是差分数组

for(int i=1;i<=N;i++)
{
    cin>>a[i];
    add(i,a[i]-a[i-1]);
}

现在你们可能有一个大胆的想法 : 怎么实现区间修改区间查询

下面就是奇技淫巧时间。 (标题已上线)

还是要用差分数组, 下面我们简单推个式子。

所以我们就可以开两个数状数组, 一个里面放c[i],一个里面放 i×c[i],就能实现区间查询了

除了每次修改改的是两个数组, 其他操作都一样

下面是代码

#include<bits/stdc++.h>
#define ull unsigned long long
#define lowbit(a) (a&-a)
#define MAXN 200005
using namespace std;
int N,M,a[MAXN];
ull c1[MAXN],c2[MAXN];
void add(int pos,ull x)
{
    for(int i=pos;i<=N;i+=lowbit(i))
        c1[i]+=x,c2[i]+=x*pos;
}
ull sum(int pos)                    //[1,pos]区间和
{
    ull s=0;
    for(int i=pos;i;i-=lowbit(i))
        s+=c1[i]*(pos+1)-c2[i];
    return s;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        cin>>a[i];
        add(i,a[i]-a[i-1]);
    }
    cin>>M;
    while(M--)
    {
        int P,X,Y;
        ull Z;
        cin>>P;
        if(P==1)
        {
            cin>>X>>Y>>Z;
            add(Y+1,-Z);
            add(X,Z);
        }
        else if(P==2)
        {
            cin>>X>>Y;
            cout<<sum(Y)-sum(X-1)<<endl;
        }
    }
    return 0;
}

可以到 http://codevs.cn/problem/1082/ 交一下练练手

好了就说这么多了。

其实, 我想去学线段树了。。。

时间: 2024-12-19 09:10:20

树状数组的基本用法的相关文章

poj 3321 Apple Tree(树状数组)

辉煌北大的月赛题质量真高啊,这种树状数组真难想到. 树状数组的基本用法是区间,单点的应用,起初这个怎么都想不到如何套用到树状数组. 转化方法是 将树上的节点信息查询,转为深度优先中节点顺序(代表结点编号).进结点与出结点分别代表该结点管辖范围. 题目大意级是说,给你一颗树,最初每个节点上都有一个苹果,有两种操作:修改(即修改某一个节点,修改时这一个节点苹果从有到无,或从无到有)和查询(查询某一个节点他的子树上有多少个苹果). 由于此题数据比较大(N<=10^5),而且不是标准的二叉树,所以这里我

树状数组的另一种用法(离散化存数)

这个操作就是对每一个数加完之后add( x , k ),再将这个数减回去add(x+1 , k)的一个操作,执行完这个操作之后,树状数组里存的就不再是一段的和了而是每个数的离散. 这样对于你要对一个区间(x,y)添加一个数k的话,只需要add(x , k)然后对y后边的数剪去k.add(y+1 , -k)注意是-k,我们就讲这个区间的每一个数都添加进了这个区间了. 求和的话,只能求一个数x,因为树状数组不再是全部数的和了,从x到1的lobit加起来才是x这个数的值. 直接把洛谷的模板题搬出来用:

树状数组

树状数组                   转自:      By 岩之痕  http://blog.csdn.net/zearot/article/details/45028723 一.概述 树状数组是一种 用数组进行存储的 自下而上进行操作的  多叉树. 以下叙述中,A为原数组,C为树状数组所用的数组,B为特殊情况需要用到的辅助数组. 最基本的应用就是维护一个支持两种操作的数列:1.让A[i]加上某数X     2.求一个区间A[L] + A[L+1] + ... + A[R] 的和. 树

树状数组大杂烩

一.引言 作为胸牌退役狗决定再搞一发noip=.= 今天遇到好几个有关差分的暴力解法(noip就是要暴力!!!),又想起之前有个树状数组的区间修改&区间查询很玄学的表现为正确,决定想办法证明一发,但是内容单调不是我的性格,然后就有了这个大杂烩...(XX:树状数组被玩坏的日常) 本文借鉴了以下博文的部分内容,在此表示感谢分享交流,如有遗漏还请见谅(毕竟有的是一年前蒯的= =): http://blog.csdn.net/qq_21841245/article/details/43956633(关

SPOJ DQUERY D-query 离线+树状数组

本来是想找个主席树的题目来练一下的,这个题目虽说可以用主席树做,但是用这个方法感觉更加叼炸天 第一次做这种离线方法,所谓离线,就在把所有询问先存贮起来,预处理之后再一个一个操作 像这个题目,每个操作要求区间不同元素的个数,我盲目去查的话,某个元素在之前如果出现了,我把他算在当前区间也不好,算在之前的区间也不好,都会出错. 一个好的方法就是把区间排好序,针对某个区间在树状数组上更新以及查询相应值,这样能准确查出结果,但又不影响之后的查询 具体来说,先把区间按右端点进行排序(我一开始按左端点排,想错

POJ 2309 BST(树状数组Lowbit)

题意是给你一个满二叉树,给一个数字,求以这个数为根的树中最大值和最小值. 理解树状数组中的lowbit的用法. 说这个之前我先说个叫lowbit的东西,lowbit(k)就是把k的二进制的高位1全部清空,只留下最低位的1,比如10的二进制是1010,则lowbit(k)=lowbit(1010)=0010(2进制),介于这个lowbit在下面会经常用到,这里给一个非常方便的实现方式,比较普遍的方法lowbit(k)=k&-k,这是位运算,我们知道一个数加一个负号是把这个数的二进制取反+1,如-1

POJ 2029 Get Many Persimmon Trees (二维树状数组 or DP)

题意:一个H * W的大矩形,里面的某些格子种有树.现在要你找出一个h * w的小矩形,使得里面树的数量最多,问最多有多少棵树 是二维树状数组基础用法,边输入边更新有树的点,建完树后就可以查询每个(1,1)到(x,y)为对顶点的矩形中共有多少棵柿子树. 算法复杂度 O(H*W*lgH*lgW) 但是由于这题的柿子树一旦确定位置后就没有更新位置,所以不需要用树状数组也可,直接用dp统计每个(1,1)到(x,y)为对顶点的矩形中共有多少棵柿子树. 统计的状态转移方程是: for(int i=1;i<

POJ 2352 Stars(树状数组 or 线段树)

链接: http://poj.org/problem?id=2352 题目大意: 在坐标上有n个星星,如果某个星星坐标为(x, y), 它的左下位置为:(x0,y0),x0<=x 且y0<=y.如果左下位置有a个星星,就表示这个星星属于level x 按照y递增,如果y相同则x递增的顺序给出n个星星,求出所有level水平的数量. 思路: 由于输入的顺序,对于第i颗星星,它的等级是之前输入的星星中,横坐标x小于等于i星横坐标的那些星星的总数量(前面的y一定比后面的y小). 所以是查询+更新操作

POJ2155 Matrix 【二维树状数组】+【段更新点查询】

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17766   Accepted: 6674 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1