最近学习了一下树状数组,这道题纠结了很久,终究是因为没有明白树状数组怎么用。
感觉网上许多大神都只是讲原理,对于我们这些初学的菜鸟恐怕都被吓跑了。
这里我就以实用主义说一下使用方法(其实我觉得其原理应该能对我们更有启发,也许会带来很多潜在的好处):
这里需要注意的是,bit的实现代码中的bit数组一开始必须清零,这个数组并不是用来储存元素的,而是为实现这个数据结构而存在的。 你需要存储的元素是要通过那个add函数添加的,而求和则是要通过sum函数实现的,而这个bit数组的结构并不是对于一个新手很容易理解的,我们也大可不必关心这个。
另外要注意一个地方,在add函数里那个n,要开的足够大,不然你是添加不进去的,比如你要是把n=10,求sum(100) 会得到0 。
举个例子: 输入n个元素,求前n个元素的和。代码如下
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int bit[1000],n; int sum(int i) { int s = 0; while(i>0) { s+=bit[i]; i-=i& -i; } return s; } int add(int i,int x){ while(i <= n){ bit[i] += x; i += (i & -i); } } int main() { while(~scanf("%d",&n)) { memset(bit,0,sizeof(bit)); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); add(i,x); } for(int i=1;i<=n;i++) printf("%d\n",sum(i)); } return 0; }
相信看了上面的代码就可以很清晰的明白了,第几个元素,是要输入进add函数的,你输入的i是几,那么这个元素就是树状数组中的第几个元素。与bit数组无关,这个数组只是为了实现特定的数据结构而存在的辅助函数罢了。
该题代码是参考了别人的。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<map> using namespace std; typedef long long ll; const int max_n = 20000+4; ll cnt_bit[20005]={0},distance_bit[20005]={0}; int n; struct point { int v,x; }a[20005]; bool cmp(point a,point b) { return a.v<b.v; } ll sum_(ll *bit,int i) { ll s = 0; while(i>0) { s+=bit[i]; i-=i & -i; } return s; } ll sum(ll *a,int i,int j) { return sum_(a,j-1) - sum_(a,i-1); } void add(ll *bit,int i,int x) { while(i<=max_n) { bit[i] += x; i += i&-i; } } int main() { ll tot = 0; scanf("%d",&n); memset(cnt_bit,0,sizeof(cnt_bit)); memset(distance_bit,0,sizeof(distance_bit)); for(int i=0;i<n;i++) scanf("%d%d",&a[i].v,&a[i].x); sort(a,a+n,cmp); for(int i=0;i<n;i++) { int v = a[i].v; int x = a[i].x; ll left = sum(cnt_bit,1,x) ; ll right = sum(cnt_bit,x+1,max_n); tot+=((left*x-sum(distance_bit,1,x)) + (sum(distance_bit,x+1,max_n)-right*x))*v; add(cnt_bit,a[i].x,1); add(distance_bit,a[i].x,a[i].x); } printf("%lld\n",tot); return 0; }
时间: 2024-10-12 14:08:08