树状数组

19市赛 树状数组 第k个糖果

爱⌒轻易说出口 提交于 2020-01-14 00:39:59
题意: 口袋里可以放进不同大小的糖果,也可以拿出不同大小的糖果。查询过程中第k小的糖果体积是多少 输入T,有T组,接下来是输入m次操作 m行输入op和x 当op等于1的时候,放进x大小的糖果 当op等于2的时候,拿进x大小的糖果 当op等于3的时候,查询第x小的糖果,并输出答案 思路:二分+树状数组(比赛时限) 这里写一个优化的树状数组的写法 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<string> 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define inf 0x3f3f3f3f 9 #define ll long long 10 #define lowbit(b) b&(-b) 11 using namespace std; 12 const int maxn=1e5+10; 13 int c[maxn],f[20]; 14 inline int read() { 15 char ch = getchar(); int x = 0, f = 1; 16 while(ch < '0' || ch > '9') { 17 if(ch == '-') f =

luogu AT2300 Snuke Line |树状数组

回眸只為那壹抹淺笑 提交于 2020-01-13 19:36:59
有一趟列车有 M+1 个车站,从 0 到 M 编号。有 N 种商品,第 i 种只在编号 [li,ri] 的车站出售。一辆列车有一个预设好的系数 d,从 0 出发,只会在 d 的倍数车站停车。对于 d 从 1 到 M 的列车,求最多能买到多少种商品。 把区间放进树状数组里,logn查询 但是长区间可能会算重复,所以先把长度区间小于d的区间放进去 长度大于等于d的必定会有交,所以直接统计答案 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int _=3e5+10; int n,m,c[_]; inline void add(int x,int y){ for(;x<=m;x+=x&(-x))c[x]+=y; } inline int sum(int x){ int res=0; for(;x;x-=x&(-x))res+=c[x]; return res; } struct node{ int l,r,len; }e[_]; inline bool cmp(node t1,node t2){ return t1.len<t2.len; } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++)

树状数组

烂漫一生 提交于 2020-01-11 03:07:36
附上学习PPT: 传送门 概念 树状数组或者二叉索引树也称作Binary Indexed Tree,又叫做Fenwick树;它的查询和修改的时间复杂度都是 log(n) ,空间复杂度则为 O(n) ,这是因为树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描。通常使用在高效的计算数列的前缀和,区间和。 其中a数组就是原数组,c数组则是树状数组,可以发现 C1 = A1 C2 = A1+A2 C3 = A3 C4 = A1+A2+A3+A4 C5 = A5 C6 = A5+A6 C7 = A7 C8 = A1+A2+A3+A4+A5+A6+A7+A8 原理 lowbit 它通过公式来得出k,其中k就是该值从末尾开始0的个数。然后将其得出的结果加上x自身就可以得出当前节点的父亲节点的位置或者是x减去其结果就可以得出上一个父亲节点的位置。比如当前是6,二进制就是0110,k为2,那么6+2=8,而C(8)则是C(6)的父亲节点的位置;相反,6-2=4,则是C(6)的上一个父亲节点的位置。 int lowbit(int x) { return (x & (-x)); } 注意:lowbit无法处理0的情况,因为它的结果也是0,那么最终就是一个死循环,所以,树状数组全部设置成以1开始的下标 单点修改 当我们要对最底层的值进行更新时,那么它相应的父亲节点存储的和也需要进行更新,所以 修改

掌握树状数组~彻底入门

我怕爱的太早我们不能终老 提交于 2020-01-09 08:54:39
前言 最近初学树状数组,原理还不是太理解,等自己什么时候完全理解了再自己总结一番。 掌握树状数组~彻底入门 先贴一下树状数组的模板代码: int lowbit(int i) { return i & -i;//或者是return i-(i&(i-1));表示求数组下标二进制的非0最低位所表示的值 } void update(int i,int val)//单点更新 { while(i<=maxn) { c[i]+=val; i+=lowbit(i);//由叶子节点向上更新树状数组C,从左往右更新 } } int sum(int i)//求区间[1,i]内所有元素的和 { int ret=0; while(i>0) { ret+=c[i];//从右往左累加求和 i-=lowbit(i); } return ret; } 模板中最常见的三个函数:①取数组下标二进制非0最低位所表示的值;②单点更新;③区间查询。树状数组,顾名思义是树状的数组,我们首先引入二叉树,叶子节点代表A[1]~A[8]。 现在变形一下: 现在定义每一列的顶端节点C数组(其实C数组就是树状数组),如图: C[i]代表子树的叶子节点的权值之和,如图可以知道: C[1]=A[1]; C[2]=A[1]+A[2]; C[3]=A[3]; C[4]=A[1]+A[2]+A[3]+A[4]; C[5]=A[5]; C[6]=A

树状数组专题总结1

℡╲_俬逩灬. 提交于 2020-01-09 05:28:05
如果给定一个数组,要你求里面所有数的和,一般都会想到累加。但是当那个数组很大的时候,累加就显得太耗时了,时间复杂度为O(n),并且采用累加的方法还有一个局限,那就是,当修改掉数组中的元素后,仍然要你求数组中某段元素的和,就显得麻烦了。所以我们就要用到树状数组,他的时间复杂度为O(lgn),相比之下就快得多。下面就讲一下什么是树状数组: 一般讲到树状数组都会少不了下面这个图: 下面来分析一下上面那个图看能得出什么规律: 据图可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。 分析上面的几组式子可知,当 i 为奇数时,ci=ai ;当 i 为偶数时,就要看 i 的因子中最多有二的多少次幂,例如,6 的因子中有 2 的一次幂,等于 2 ,所以 c6=a5+a6(由六向前数两个数的和),4 的因子中有 2 的两次幂,等于 4 ,所以 c4=a1+a2+a3+a4(由四向前数四个数的和)。 (一)有公式:cn=a(n-a^k+1)+.........+an(其中 k 为 n 的二进制表示中从右往左数的 0 的个数)。 那么,如何求 a^k 呢

树状数组(一维)

牧云@^-^@ 提交于 2020-01-09 04:17:26
变形一下 现在定义每一列的顶端结点C[]数组 下面说代码 int lowbit(int t) { return t&(-t); } //-t 代表t的负数 计算机中负数使用对应的正数的补码来表示 //例如 : // t=6(0110) 此时 k=1 //-t=-6=(1001+1)=(1010) // t&(-t)=(0010)=2=2^1 C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i]; C[i]=A[i-lowbit(i)+1]+A[i-lowbit(i)+2]+......A[i]; 区间查询 ok 下面利用C[i]数组,求A数组中前i项的和 举个例子 i=7; sum[7]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7] ; 前i项和 C[4]=A[1]+A[2]+A[3]+A[4]; C[6]=A[5]+A[6]; C[7]=A[7]; 可以推出: sum[7]=C[4]+C[6]+C[7]; 序号写为二进制: sum[(111)]=C[(100)]+C[(110)]+C[(111)]; 再举个例子 i=5 sum[5]=A[1]+A[2]+A[3]+A[4]+A[5] ; 前i项和 C[4]=A[1]+A[2]+A[3]+A[4]; C[5]=A[5]; 可以推出: sum[5]=C[4]+C[5]; 序号写为二进制:

树状数组:CDOJ1583-曜酱的心意(树状数组心得)

本秂侑毒 提交于 2020-01-09 02:04:27
曜酱的心意 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 131072/131072KB (Java/Others) Description Chika说希望和我一起做学园偶像的时候,我真的很开心。——WatanabeYou 曜是千歌的青梅竹马,但是Aqours成立以后,千歌似乎总是与梨子在一起,而把曜冷落了。为了让千歌知晓自己的心意,曜酱决定做一件大事!她决定把一个给定的1~n的排列{a1,a2,…,an}(1≤ai≤n),且ai各不相同),用最少的交换次数,变换成另一个1~n的排列{b1,b2,…,bn}。并且,每次只交换相邻的两个元素。也许这样做了以后,千歌能更多地注意自己吧。曜这样想。 Input 第一行是一个整数n,第二行是一个长度为n的1~n的排列a,第三行是另一个长度为n的1~n的排列b。 Output 输出一行,一个整数,表示最少的交换次数。 Sample Input 4 2 3 1 4 3 2 1 4 3 3 2 1 1 2 3 Sample Output 1 3 解题心得: 关于树状数组其实弄的不是很懂,没办法看了好久了。反正树状数组用来求区间和很不错,能够用树状数组解决的基本都能够使用线段树解决。等把树状数组理解更深入了再来写博客。 求逆序数的方法有很多,比如归并排序

[SDOI2009]HH的项链 [树状数组]

不打扰是莪最后的温柔 提交于 2020-01-09 00:58:23
1972 [SDOI2009]HH的项链 一段区间包含了多少种不同的数字 emmmm有很多种做法 莫队 主席树 线段树....我觉得这题还挺好的 我比较弱就用的树状数组 得离线 关键点是要将右端点r作为关键字 若前面出现过 就将其消掉 转移到当前 for(int i=1;i<=m;++i){ for(int j=nxt;j<=ask[i].r;++j){ if(in[a[j]]) update(in[a[j]],-1); update(j,1),in[a[j]]=j; } 这一坨把它比比划划就能明白了 尽量将其往后挪 因为是离线 (语无伦次) #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register const int N=500000+5,M=200000+5,inf=0x3f3f3f3f,P=99999997; int n,m,tree[N<<2],a[N<<1],in[N<<1],ans[N<<1];

树状数组

被刻印的时光 ゝ 提交于 2020-01-09 00:38:00
摘抄于 半根毛线_树状数组彻底入门 int lowbit(int t) { return t&(-t); } void add(int x,int y) { for(int i=x;i<=n;i+=lowbit(i)) tree[i]+=y; } int getsum(int x) { int ans=0; for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i]; return ans; } 树状数组 重点是在 树状 的数组 大家都知道二叉树吧 叶子结点代表A数组A[1]~A[8] 现在变形一下 现在定义每一列的顶端结点C[]数组 如下图 C[i]代表 子树的叶子结点的权值之和// 这里以求和举例 如图可以知道 C[1]=A[1]; C[2]=A[1]+A[2]; C[3]=A[3]; C[4]=A[1]+A[2]+A[3]+A[4]; C[5]=A[5]; C[6]=A[5]+A[6]; C[7]=A[7]; C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]; 下面观察如下图 将C[]数组的结点序号转化为 二进制 1=(001) C[1]=A[1]; 2=(010) C[2]=A[1]+A[2]; 3=(011) C[3]=A[3]; 4=(100) C[4]=A[1]+A[2]+A[3]+A[4]; 5=

树状数组求逆序对

别来无恙 提交于 2020-01-08 23:36:26
对于数的范围比较小,我们可以这样来求解逆序对。 树状数组b[val]表示的是val在数组中出现的次数。 我们倒序扫描原数组a,对于位置i,由于树状数组里面保存的是val出现的次数,我们先用树状数组求出当前树状数组中比a[i]这个值小的元素的个数,由于是倒序扫描,之前加入树状数组中的数的位置都在i后面,因此我们就把求得的比a[i]这个值小的元素的个数累加到答案中。 for(int i=n;i;i--) { ans+=ask(a[i]-1); add(a[i],1); } 这是针对数的范围较小采取的方法,当数的范围较大时,我们对数据经行排序,然后离散化。下面给出一种求解方法。 #include<algorithm> #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 5e5 + 10; typedef long long ll; #define lowbit(x) (x&(-x)) int n, m, c[N], a[N], b[N]; void add(int x) { for (; x <= n; x += lowbit(x)) c[x]++; } int ask(int x) { int s = 0; for (; x > 0; x -= lowbit(x