树状数组(Binary Indexed Tree, Fenwick Tree)的C++实现

1,221 阅读2分钟

Binary Indexed Tree or Fenwick Tree

Binary Indexed Tree or Fenwick Tree | Fenwick (Binary Indexed) Trees | 树状数组

前缀和及其更新

We have an array arr[0 . . . n-1]. We would like to 1 Compute the sum of the first i elements. 2 Modify the value of a specified element of the array arr[i] = x where 0 <= i <= n-1.

一个正数和自己的负数作与运算是自己最低二进制数位为1的值,如6&(-6)=2, 9&(-9)=1, 即

i&(-i) = (2^km+...+2^k1+2^k0) & (-(2^km+...+2^k1+2^k0))=2^k0, 
where 0<=k0<k1<..<km<overflow

原数组下标从1开始,下标为i的对应在树状数组上的父节点为parent(i):当update时,parent(i)=i+i&(-i);当getSum时,parent(i)=i-i&(-i)。

                     21

          7                      30

    3           5          13

 2     1     2     4     6     8

 2  1  1  3  2  3  4  5  6  7  8  9

 1  2  3  4  5  6  7  8  9 10 11 12

// C++ code to demonstrate operations of Binary Index Tree 
#include <iostream> 

using namespace std;

/*         n --> No. of elements present in input array.
	BITree[0..n] --> Array that represents Binary Indexed Tree.
	arr[0..n-1] --> Input array for which prefix sum is evaluated. */

	// Returns sum of arr[0..index]. This function assumes 
	// that the array is preprocessed and partial sums of 
	// array elements are stored in BITree[]. 
int getSum(int BITree[], int index)
{
	int sum = 0; // Iniialize result 

	// index in BITree[] is 1 more than the index in arr[] 
	index = index + 1;

	// Traverse ancestors of BITree[index] 
	while (index > 0)
	{
		// Add current element of BITree to sum 
		sum += BITree[index];

		// Move index to parent node in getSum View 
		index -= index & (-index);
	}
	return sum;
}

// Updates a node in Binary Index Tree (BITree) at given index 
// in BITree. The given value 'val' is added to BITree[i] and  
// all of its ancestors in tree. 
void updateBIT(int BITree[], int n, int index, int val)
{
	// index in BITree[] is 1 more than the index in arr[] 
	index = index + 1;

	// Traverse all ancestors and add 'val' 
	while (index <= n)
	{
		// Add 'val' to current node of BI Tree 
		BITree[index] += val;

		// Update index to that of parent in update View 
		index += index & (-index);
	}
}

// Constructs and returns a Binary Indexed Tree for given 
// array of size n. 
int* constructBITree(int arr[], int n)
{
	// Create and initialize BITree[] as 0 
	int* BITree = new int[n + 1];
	for (int i = 1; i <= n; i++)
		BITree[i] = 0;

	// Store the actual values in BITree[] using update() 
	for (int i = 0; i < n; i++)
		updateBIT(BITree, n, i, arr[i]);

	// Uncomment below lines to see contents of BITree[] 
	//for (int i=1; i<=n; i++) 
	//     cout << BITree[i] << " "; 

	return BITree;
}


// Driver program to test above functions 
int main()
{
	int freq[] = { 2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9 };
	int n = sizeof(freq) / sizeof(freq[0]);
	int* BITree = constructBITree(freq, n);
	cout << "Sum of elements in arr[0..5] is "
		<< getSum(BITree, 5);

	// Let use test the update operation 
	freq[3] += 6;
	updateBIT(BITree, n, 3, 6); //Update BIT for above change in arr[] 

	cout << "\nSum of elements in arr[0..5] after update is "
		<< getSum(BITree, 5);

	return 0;
}

[编程题]小易的英语软件

网易2020校招笔试- 系统开发/研发工程师(提前批)

[编程题]小易的英语软件

小易是班级的英语课代表, 他开发了一款软件开处理他的工作。 小易的软件有一个神奇的功能,能够通过一个百分数来反应你的成绩在班上的位置。“成绩超过班级 ...% 的同学”。 设这个百分数为 p,考了 s 分,则可以通过以下式子计算得出 p: p = ( 分数不超过 s 的人数 - 1) 班级总人数 突然一天的英语考试之后,软件突然罢工了,这可忙坏了小易。成绩输入这些对于字写得又快又好的小易当然没有问题,但是计算这些百分数……这庞大的数据量吓坏了他。 于是他来找到你,希望他编一个程序模拟这个软件:给出班级人数 n,以及每个人的成绩,请求出某几位同学的百分数。

输入描述: 第一行一个整数 n,表示班级人数。 第二行共 n 个自然数,第 i 个数表示第 i 位同学的成绩 a_i。 第三行一个整数 q,表示询问的次数。 接下来 q 行,每行一个数 x,表示询问第 x 位同学的百分数。

输出描述: 输出应有 q 行,每行一个百分数,对应每一次的询问。 为了方便,不需要输出百分号,只需要输出百分号前的数字即可。四舍五入保留六位小数即可。

#include<iostream>
#include<vector>
#include<unordered_map>
#include <iomanip>
using namespace std;

vector<int> updateBIT(vector<int>& BIT, int i, int val, int N)
{
	i = i + 1;
	while (i <= N)
	{
		BIT[i] += val;
		i += i & (-i);
	}
	return BIT;
}

int getSum(vector<int>& BIT, int idx)
{
	int sum = 0;
	idx += 1;
	while (idx > 0)
	{
		sum += BIT[idx];
		idx -= idx & (-idx);
	}
	return sum;
}


int main()
{
	// 树状数组BIT表示考了i分的人数前缀和
    vector<int> score(10001, -1); // score[i]为第i个人的成绩
	int n;
	cin >> n;
	int N = 153;
	vector<int> BIT(N, 0); // [0,150]分 -> idx为[1,151]
	for (int i = 1; i <= n; i++)
	{
		cin >> score[i]; 
		BIT = updateBIT(BIT, score[i] + 1, 1, N); // 考了score[i]的分数的人增加一个
	}

	int q;
	cin >> q;
	while (q--)
	{
		int temp;
		cin >> temp;
		// p = (分数不超过 s 的人数 - 1)  班级总人数
		double p = (double)(getSum(BIT, score[temp] + 1) - 1) * 100.0 / (double)(n);
		printf("%.6f\n",p);
	}

	return 0;
}