二叉索引树

Posted -iris-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉索引树相关的知识,希望对你有一定的参考价值。

树状数组

又名二叉索引树,是一种与线段树相似的数据结构
他们能使对一个区间的数修改以及查询的速度提升许多

树状数组模板1

#include<iostream>
#include<cstdio>

using namespace std;

int tree[2333333];
int sum[233333];
int a[2333333];
int n,m;

#define lowbit(x)  (x&(-x))

inline void init()
{
	for(int x,i=1;i<=n;i++)
	{
		cin>>x;
		sum[i]=sum[i-1]+x;
		tree[i]=sum[i]-sum[i-lowbit(i)];
	}
}

inline void add(int a,int val)
{
	while(a<=n)
	{
		tree[a]+=val;
		a+=lowbit(a);
	}
}

inline int query(int a)
{
	int res=0;
	
	while(a)
	{
		res+=tree[a];
		a-=lowbit(a);
	}
	
	return res;
}

int main()
{
	
	
	ios_base::sync_with_stdio(false);
	cout.tie(NULL);
	cin.tie(NULL);
	
	cin>>n>>m;
	
	init();
	
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		
		cin>>x>>y>>z;
		
		if(x == 1)
		{
			add(y,z);
		}
		else{
			cout<<query(z)-query(y-1)<<‘
‘;
		}
	}
}

中间有一个小小的卡常

inline void init()
{
	for(int x,i=1;i<=n;i++)
	{
		cin>>x;
		sum[i]=sum[i-1]+x;
		tree[i]=sum[i]-sum[i-lowbit(i)];
	}
}

该函数能将初始化树状数组的复杂度优化从O(nlogn)->O(n)



树状数组模板2

#include<iostream>
#include<cstdio>

using namespace std;

int tree[2333333];
int c[2333333];
int n,m;

inline int lowbit(int x) {return x&-x;}

inline void add(int a,int val)
{
	while(a<=n)
	{
		tree[a]+=val;
		a+=lowbit(a);
	}
}

inline int query(int a)
{
	int res=0;
	
	while(a)
	{
		res+=tree[a];
		a-=lowbit(a);
	}
	
	return res;
}

int main()
{
	
	ios_base::sync_with_stdio(false);
	cout.tie(NULL);
	cin.tie(NULL);
	
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		cin>>c[i];
	}
	
	for(int i=1;i<=m;i++)
	{
		int l,x,y,z;
		
		cin>>l;
		if(l == 1)
		{
			cin>>x>>y>>z;
			add(x,z);
			add(y+1,-z);
		}
		else
		{
			cin>>x;
			int U=query(x)+c[x];
			cout<<U<<‘
‘;
		}
	}
}
  • 对序列进行区间修改
  • 我们使用了另一个树状数组来辅助修改
  • 记录左右端点的修改
  • 当我们访问b的前缀和时
  • 就相当于访问之前操作对[1~x]的影响

线段树模板1

#include<iostream>
#include<cstdio>

using namespace std;

const long long  maxn=1e5+5;

long long  n,m;
long long  sum[maxn];
long long  tree[2][maxn];

inline long long  lowbit(long long  x) {return x&-x;}

inline void add(long long  k,long long  a,long long  val)
{
	
	while(a<=n)
	{
		tree[k][a]+=val;
		a+=lowbit(a);
	}

}

inline long long  query(long long  k,long long  a)
{
	long long  res=0;
	
	while(a)
	{
		res+=tree[k][a];
		a-=lowbit(a);
	}
	
	return res;
}



int main()
{
	
	
	cin>>n>>m;
	
	long long  x;
	
	for(long long  i=1;i<=n;i++)
	{
		cin>>x;
		sum[i]=sum[i-1]+x;
	}	
	
	for(long long  i=1,x,y,z,g;i<=m;i++)
	{
		cin>>x>>y>>z;
		if(x == 1)
		{
			cin>>g;
			add(1,y,g);
			add(1,z+1,-g);
			add(0,y,y*g);
			add(0,z+1,-(z+1)*g);
		}
		else{
			cout<<(sum[z]+(z+1)*query(1,z)-query(0,z))-(sum[y-1]+y*query(1,y-1)-query(0,y-1))<<‘
‘;
		}
	}
}

对单点查询=访问原值+b树状数组前缀和
所以区间查询相当于对多个点进行单点查询
那么a前缀和整体增加值为
(sum_{i=1}^x{sum_{j=1}^i{b[j]}})
(sum_{i=1}^x{sum_{j=1}^i{b[j]}} = sum_{i=1}^x{(x-i+1)*b[i]} = (x+1)sum_{i=1}^xb[i] - sum_{i=1}^x{i*b[i]})

所以我们增加一个树状数组,维护 (i*b[i])的前缀和(sum_{i=1}^x{i*b[i]})

另外我们维护原数组前缀和sum,对于每条 Q l r
可得出
访问原值前缀和与上述两个树状数组的值在套用上式与另一端点作差即可得出答案


end








以上是关于二叉索引树的主要内容,如果未能解决你的问题,请参考以下文章

二叉索引树

[转] MySQL索引原理

二叉树红黑树HashB+树

LeetCode810. 黑板异或游戏/455. 分发饼干/剑指Offer 53 - I. 在排序数组中查找数字 I/53 - II. 0~n-1中缺失的数字/54. 二叉搜索树的第k大节点(代码片段

MySQL 索引与 B+ 树

二叉树添加索引