树状数组

树状数组

倖福魔咒の 提交于 2020-03-30 11:02:57
树状数组的作用和线段树基本一致,主要有更改和查询两种 一、单点修改和区间查询( 洛谷p3374 ) 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<queue> #include<ctime> #include<vector> #include<set> #include<map> #include<stack> using namespace std; int c[2000000]; int n; int lowbit(int x){ return x&(-x); } void add(int pos,int x){ while(pos<=n){ c[pos]+=x; pos+=lowbit(pos); } } int sum(int x){ int ans=0; while(x){ ans+=c[x]; x-=lowbit(x); } return ans; } int main() { int m,i,j,k,x,y; cin>>n>>m; for(i=1;i<=n;i++){ scanf("%d",&x); add(i

poj2352_树状数组&&线段树

那年仲夏 提交于 2020-03-30 10:35:54
题目链接 两种写法所用到的思维是一样的,都是在输入一个星星位置的时候, 先查询比他的x小的星星,再把它插入到树or数组中。 线段树写法: #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define maxn 32000+10 int sum[maxn<<2],level[maxn]; int n; void update(int l,int r,int rt,int data) { sum[rt]++; if(l==r) return; int mid=(l+r)/2; if(data<=mid) update(l,mid,rt<<1,data); else update(mid+1,r,rt<<1|1,data); } int query(int left,int right,int l,int r,int rt) { if(left==l&&right==r) { return sum[rt]; } int mid=(l+r)/2; if(right<=mid) { return query(left,right,l,mid,rt<<1); } else if(left>mid) return query(left,right,mid+1,r,rt<<1|1);

树状数组总结

本小妞迷上赌 提交于 2020-03-30 09:18:43
http://www.java3z.com/cwbwebhome/article/article1/1369.html 推荐的博文 referrence: http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees 对于正整数,我们定义lowbit(x)为x的二进制表达式中最右边1所对应的值。对于节点i,如果它是左子节点,那么父节点的编号就是i+lowbit(i),如果它是右子节点,那么父节点的编号是i-lowbit(i),构造一个辅助数组C,其中 Ci=A[i-lowbit(i)+1]+...+A[i]。 前缀和S[i]:顺着节点i往左走,边走边“往上爬”,把沿途经过的C[i]累加起来 修改一个A[i],从C[i]开始往右走,边走边“往上爬”,沿途修改所有节点对应的C[i] 注意:树状数组的下标永远是从1开始的 树状数组求逆序对的原理: 前面有i-1个数,把每次输入的数看作树状数组的下标,设置增加的变量为1,算其前缀和(有多少个1就有多少个顺序对),然后减去顺序对就是答案,方案有两种(本质是一样的): 1、 ans+=(i-1-sum(a)); add(a); 2、 add(a); ans+=(i-sum(a)); 模板: #define MARK 50005 int c

专题训练之树状数组

一曲冷凌霜 提交于 2020-03-30 09:18:20
推荐几个博客:https://blog.csdn.net/int64ago/article/details/7429868搞懂树状数组 https://blog.csdn.net/z309241990/article/details/9615259区间修改 https://blog.csdn.net/whereisherofrom/article/details/78922383完整版+题集 http://www.cnblogs.com/wuyiqi/archive/2011/12/25/2301071.html二进制思想求第k大数 http://www.cnblogs.com/oa414/archive/2011/07/21/2113234.html二分/二进制思想求第k大数 一维树状数组模板(区间求和、单点修改) 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=1e5+10; 6 int bit[maxn],n; 7 8 int lowbit(int x) 9 { 10 return x&(-x); 11 } 12 13 void add(int k,int num) 14 { 15 while ( k<=n ) { 16

树状数组求逆序数的原理

橙三吉。 提交于 2020-03-30 09:13:13
求逆序数的方法有很多,比如归并排序,但本文重点讲一下如何用树状数组来求逆序数。 当数据的范围较小时,比如maxn=100000,那么我们可以开一个数组c[maxn],来记录前面数据的出现情况,初始化为0;当数据a出现时,就令c[a]=1。这样的话,    欲求某个数a的逆序数,只需要算出在当前状态下c[a+1,maxn]中有多少个1,因为这些位置的数在a之前出现且比a大。但是若每添加一个数据a时,就得从a+1到     maxn搜一遍,复杂度太高了。树状数组却能很好的解决这个问题,同样开一个数组d[maxn],初始化为0,d[i]记录下i结点所管辖范围内当前状态有多少个数;当添加数    据a时,就向上更新d,这样一来,欲求a的逆序数时,只需要算sum(maxn)-sum(a);sum(i)表示第i个位置之前出现了多少个1.     举个例子:有5个数,分别为5 3 4 2 1,当读入数据a=5时,c为:0,0,0,0,1;d为:0,0,0,0,1;当读入数据a=3时,c为:0,0,1,0,1;d为:0,0    1,1,1;当读入数据a=4时,c为:0,0,1,1,1;d为:0,0,1,2,1;…………。 此思想的关键在于,读入数据的最大值为maxn,由于maxn较小,所以可以用数组来记录状态。当maxn较大时,直接开数组显然是不行了,这是的解决办法就是离散   化。所谓离散化

【数据结构】树状数组

ぃ、小莉子 提交于 2020-03-30 09:12:42
【树状数组】   顾名思义:本质是数组,逻辑上是被构造出来的二叉树,方便求前缀和,以及更新元素值   关键:设原数组为A,设构造出来的树状数组为 C,令   C i = A i-lowbit(i) + 1 + A i-lowbit(i) + 2 + .......... + A i , 其中lowbit(i) = i & (-i)    所以   操作1:求前缀和 Si = Ci + Ci-lowbit(i) + ...... 直到 C 的下标 index = i - lowbit(i) = 1   操作2:元素A[x] 的值加上 y ,需要更新包含A[x] 的区间:                        C[x] = C[x] + y                        x = x + lowbit(x) C[x] = C[ x ] + y                         ........                        直到 x > n (n 为元素个数)   可以得以上两个操作的时间复杂度均为 O( logn ) 【应用】    求逆序对 【优化】    【模板】 /*树状数组模板注意数组C[]下标是从1开始by chsobin*/const int maxn = 32005; int c[maxn]; void init(){

【数据结构】树状数组

好久不见. 提交于 2020-03-30 09:12:24
使用目的 树状数组是为了解决多次单点更新,区间查询等问题的数据结构。 树状数组的更新与查询复杂度均为O(logn)。 为了方便理解树状数组的优势,这里先给出一道题目: 给一大小固定的A数组,现用户可随意更改此数组的任何n个元素为任何值,且用户还想知道每次更改元素后数组中下标从0到m的元素的和。请你用快速的方法解决这个问题。 那么最简单的思路是在每次查询时从0到m做一次求和。但当更改和查询次数巨大的时候,我们不得不换一种思路以免超时。 那么树状数组就是可选的一种结构。 数据结构 为了解决问题,我们希望在求和的时候不要一个一个元素求和,而是一段一段求和。 因此,我们考虑设计一些节点存储一段元素的和,在用户求和的时候可以一段一段求。并且这个节点的数量应该恰到好处,因为我们后续更新这些节点必须快速方便。 庆幸的是有一种方便且快速的数据结构可供我们使用,那就是树状数组。 (这里引用了他人图片,原作者信息在图片上) 为了构造这样一个结构,我们先把数组A的一些元素“提”起来,做成图中的数组C的样子。 我们考虑把数组C看成上述的节点,这些节点存储着相应的一段元素的和。 为了方便找到其中的规律,把数字的二进制形式写出来: 0001 C[1] = A[1] 0010 C[2] = C[1] + A[2] = A[1] + A[2] 0011 C[3] = A[3] 0100 C[4] = C[2] +

学习:树状数组

眉间皱痕 提交于 2020-03-30 09:11:33
先上一道 题目 : 题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某一个数加上x 求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3个整数,表示一个操作,具体如下: 操作1: 格式:1 x k 含义:将第x个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整数,即为所有操作2的结果。 输入输出样例 输入样例#1: 5 5 1 5 4 2 3 1 1 3 2 2 5 1 3 -1 1 4 2 2 1 4 输出样例#1: 14 16 说明 时空限制:1000ms,128M 数据规模: 对于30%的数据:N<=8,M<=10 对于70%的数据:N<=10000,M<=10000 对于100%的数据:N<=500000,M<=500000 想暴力过?不存在的(底层优化不敢说)。于是,我们需要一种数据结构来进行优化。 树状数组 其实,树状数组就是一个数组。 如果我们有一个数组 \(a\) ,我们可以构造一个数组 \(C\) ,使 \(C[i]=a[i-2^k+1]+\cdots+a[i]\) , \(k\) 为 \(i\) 在二进制下末尾 \(0\) 的个数。

树状数组

会有一股神秘感。 提交于 2020-03-30 09:11:14
树状数组 简介 为什么需要树状数组? 举一个简单的例子,有一个数组[ 9 , 3 , 2 , 5 , 7 ],当我们需要计算数组任意X~X+N项元素的和,若采用传统方式,则需要从X开始一路加到X+N,需要的时间复杂度o(n)。 若要进一步优化我们可以求出含有对应位置前n项和的数组,例如上述数组对应结果为T[9 , 12 , 14 , 19 , 26],若要再求X~X+N个元素的和,只需计算T[X+N] - T[X]即可,但问题是当在数组某个位置重新插入一个元素时,需要将其位置后面的所有元素都更新,时间复杂度仍是O(N) 这个时候树状数组就出现了,树状数组的插入和查询任意n项和的时间复杂度都是o(log n) 以[1 , 2 , 3 , 4 , 5 , 6 , 7 , 8]为节点的一颗完整树状数组如下图 树状数组每个节点的父节点为pos += lowbit(i),i<n lowbit是指一个整数的二进制表示,从后往前数一直到第一个1所代表的大小 例如 3 = 011 那么3的lowbit即为1    6 =0110 那么6的lowbit为 2 ​ 关于lowbit有一个很简单的求法那就是( X&~X ) 插入或更新元素 当我们需要插入一个元素时,从这个元素开始,依次更新这个节点一直到树根中所有元素 以2号节点元素加上5为例,初始化pos = 2 1.更新2号元素  3+5=8 2

PAT-1057 Stack (树状数组 + 二分查找)

主宰稳场 提交于 2020-03-27 10:07:34
1057. Stack Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd. Input Specification: Each input file contains one test case. For each case, the first line