树状数组

树状数组[BIT]

[亡魂溺海] 提交于 2019-12-02 13:06:31
1 #include <iostream> 2 using namespace std; 3 const int maxn=10000; 4 int a[maxn]; 5 int c[maxn]; 6 7 void make_c(int i){ 8 int x=i&(-i); //2^xi=i&(-i);求区间范围大小,x=2^xi 9 for(int left=i-x+1;left<=i;left++) //区间范围[i-2^x+1,i] 10 { 11 c[i]=c[i]+a[left]; //c[i]表示该区间范围内的元素之和 12 } 13 } 14 15 void updata(int i,int num,int n){ //将a[i]更改为new,更新c[i]数组 16 while(i<=n) 17 { 18 c[i]=c[i]+num; 19 i=i-i&(-i); 20 } 21 } 22 23 int sum(int i){ //前i个元素求和 24 int s=0; 25 while(i>0) 26 { 27 s+=c[i]; 28 i-=i&(-i); 29 } 30 return s; 31 } 32 33 int main(){ 34 int n; 35 cin>>n; 36 for(int i=1;i<=n;i++) 37 { 38 cin>>a[i];

树状数组(Binary Indexed Tree)

社会主义新天地 提交于 2019-12-02 12:32:43
一、概述   树状数组即Binary Indexed Tree或者Fenwick Tree,是一种用于高效处理数字的列表更新和求范围和的数据结构。它可以以O(logn)的时间得到前缀和num[1..i],并同时支持O(logn)时间内支持动态单点值的修改。   树状数组解决的问题就是存在一个长度为n的数组nums,我们如何高效的执行以下操作: update(ind,val) 将val的值加到数组的ind位置上 prefixSum(ind) 求数组前ind个位置上的数字和 rangeSum(from,to) 求数组[from..to]求数和   当执行update的数量很少,prefixSum或者rangeSum的操作很多时,我们可以为原数组nums创建一个相同大小的数组sum,sum[i]表示前i个(包括第i个)的数字和。这样prefixSum(ind)=sum[ind],rangeSum(from,to) = sum[to]-sum[from]+nums[from]. 当update的操作频率增大时,每次update(ind,val)将对数组sum的i>=ind的所有位置进行修改。树状数组就是对这种情况的一种改进。 二、建立BIT   这里我们假设一段大小为15的数组[1,4,3,2,8,7,6,5,4,10,12,14,15,9,13,11],构建后的数组是怎么样的的

树状数组

走远了吗. 提交于 2019-12-02 12:18:50
树状数组 为了表述方便,下面所有的数字,都是二进制形式下的。 拆分成特殊区间------C[i]的定义 树状数组通过特定将区间 \(\left[1,i \right]\) 通过一个特殊地规则,将区间拆分成 \(k(k \leq \log_{2}{i+1})\) 个区间 \(\left(i_{k-1},i_{k} \right], \left(i_{k-2},i_{k-1} \right],\dots,\left(0,i_1\right]]\) ,其中 \(i_k=i\) . 而所谓特殊地规则,是这样的,首先将 \(\left(l,r\right]\) ,首先将 \(r\) 用二进制表示,然后将最后一个 1 变成 0 即获得了左端点 \(l\) . 之后把 \(l\) 作为下一个区间的右端点,重复进行,直到整个区间分完了。 举个例子。假设 \(r=100011001001\) .划分的区间如下 l | r -------------- -------------- 100011001000 100011001001 100011000000 100011001000 100010000000 100011000000 100000000000 100010000000 000000000000 100000000000 我们将数 \(i\) 二进制表示形式下最后一个1的位权

洛谷 P3374 【模板】树状数组 1 线段树版

一世执手 提交于 2019-12-02 05:32:58
传送门      题目描述:   已知一个数列,你需要进行下面两种操作:   1.将某一个数加上x   2.求出某区间每一个数的和   这道题看名字就知道是树状数组的模板题,但是菜鸡的我想熟悉线段树,所以用了线段树。   思路没有什么好说的(如果不知道怎么做的,建议先学习树状数组),详情看代码。   一些小细节:     1.运算都用位运算加速     2.不要用cin,cout,亲测超时     3.对于根node,       左儿子 是 node * 2 ---->> node << 1;       右儿子是 node * 2 + 1 ---->> node<<1 | 1; 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 const int N = 5e5 + 10; 5 6 int n, m; 7 int tree[N*4]; 8 9 10 //不用建树,因为你会发现代码是一样的。。。亲测 11 12 //在pos上加上X 13 void update(int node, int l, int r, int pos, int x) 14 { 15 if(l == r) {tree[node] += x; return;} 16 int mid = (l + r) >> 1; 17 if

树状数组优化最长上升子序列

倖福魔咒の 提交于 2019-12-02 04:33:06
最长上升子序列比较暴力的写法是n 2 的,实际上我们求得就是前面的比当前小的最长上升子序列的最大值; 树状数组可以优化它; 倒过来求就是最长下降子序列; #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e5+10; typedef double dd; typedef long long ll; ll n; ll a[maxn]; ll id[maxn]; ll f[maxn],g[maxn]; ll b1[maxn],b2[maxn]; int len; ll query_front(int x) { ll ans=0; for(;x;x-=x&(-x)) ans=max(b1[x],ans); return ans; } ll query_back(int x) { ll ans=0; for(;x;x-=x&(-x)) ans=max(b2[x],ans); return ans; } void add_front(int x,ll y) { for(;x<=len;x+=x&(-x)) b1[x]=max(b1[x],y); } void add_back(int x,ll y) { for(;x<=len;x+=x&(-x)) b2[x]

【刷题】【树状数组】会场预约

天大地大妈咪最大 提交于 2019-12-02 02:57:32
A操作:有一个新的预约是从“start日”到“end日”,并且拒绝掉所有与它相冲突的预约。 执行这个操作的时候,你的系统应当返回为了这个新预约而拒绝掉的预约个数,以方便QQ与自己的记录相校对。 B操作:请你的系统返回当前的仍然有效的预约的总数。 #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; int n;char ch[10]; const int N=100003,mx=100000; int tr[N],rt[N]; int lowbit(int x) { return x&(-x); } void add(int pos,int v) { while(pos<=mx) tr[pos]+=v,pos+=lowbit(pos); } int query(int pos) { int as=0; while(pos>0) as+=tr[pos],pos-=lowbit(pos); return as; } int main() { scanf("%d",&n); int sum=0; memset(rt,-1,sizeof(rt)); while(n--) { scanf("%s",ch); if(ch[0]=='B') printf("%d\n",sum); else { int

【题解】Music Festival(树状数组优化dp)

我与影子孤独终老i 提交于 2019-12-02 02:08:37
【题解】Music Festival(树状数组优化dp) Gym - 101908F 题意:有 \(n\) 种节目,每种节目有起始时间和结束时间和权值。同一时刻只能看一个节目(边界不算),在所有种类都看过至少一遍的情况下最大收益 设 \(dp(s,i)\) 表示已经看过 \(s\) 集合中的节目,且看过的节目的结束时间是 \(i\) 的最大收益。 转移: \[ dp(s,e[t].r)=\max(dp(s,k),dp(s-e[t].id,k))+e[t].val,k\le e[t].l \] 由于 \(O(m^3)\) 不能过1000,但可以看到转移是一段前缀,所以直接树状数组优化就好。 注意转移的顺序,可以发现 \(r\) 可以作为转移状态。可能会有r相同的情况,但不影响答案。 复杂度 \(O(m^2\log m)\) //@winlere #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; inline int qr(){ register int ret=0,f=0; register char c=getchar(); while(!isdigit(c))f|=c==45,c=getchar()

树状数组模板

十年热恋 提交于 2019-12-01 16:59:19
https://vjudge.net/problem/HDU-1166 单点修改 单点查询 #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #define lowbit(x) x&(-x) using namespace std; const int M=200007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int T,n,sum[2*M]; int upd(int x,int k){ while(x<=n){ sum[x]+=k; x+=lowbit(x); } } int p_ans(int x){ int ans=0; while(x){ ans+=sum[x]; x-=lowbit(x); } return ans; } char c[25]; int main(){ int x,k,cnt=0; T=read(); while(T--){ for(int i=1;i<

uva1428树状数组

别来无恙 提交于 2019-12-01 08:13:57
用树状数组统计每个点i,左边与右边与多少个点小于a[i],然后用乘法原理和加法原理得出答案 #pragma GCC optimize(2) #include <bits/stdc++.h> #define ll long long #define ls(i) i<<1 #define rs(i) i<<1|1 using namespace std; const int N = 1e5+10; ll bit[N],lx[N],rx[N],a[N]; int lowbit(int x) { return x&(-x); } void add(int x,int val) { while(x<N) { bit[x]+=val; x+=lowbit(x); } } ll query(int x) { ll ans=0; while(x>0) { ans+=bit[x]; x-=lowbit(x); } return ans; } int main(){ int T; cin>>T; while(T--) { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } memset(bit,0,sizeof(bit)); for(int i=1;i<=n;i++) { lx[i]=query(a[i]); add(a[i],1); }

LIS 树状数组优化

孤人 提交于 2019-12-01 07:55:23
lis 众所周知 即最长上升子序列 可以用dp求解 复杂度O(n^2) 我们考虑优化 用树状数组(或者线段树) 树状数组维护区间最大值 (省去原始O(n^2)算法中的查找) 这样还能求出以i结尾的lis 二分只能求出当前序列的lis (许多题里要求lis个数什么的qwq 总之比二分方便 除了码量长 ) 还有一个小点就是可能会用到离散化( 传送门 ) 具体实现看代码 #include<bits/stdc++.h> using namespace std; int a[mxn],b[mxn],n,sz,ans; int dp[mxn],f[mxn]; int lowbit(int x){ return x&(-x); } int motify(int x,int w){ for(;x<=m;x+=lowbit(x)){ f[x]=max(f[x],w); } } int get(int x){ int temp=0; for(;x;x-=lowbit(x)){ temp=max(temp,f[x]); } return temp; } int main(){ cin>>n; for(int i=1;i<=n;i++){ scansf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); sz=unique(b+1,b+n+1)-(b+1); for