lowbit(x) = x & (-x)
查找当前元素所对应二进制的最后一个1。原理利用 负数 的补码。
#include<bits/stdc++.h>
using namespace std;
#define lowbits(x) ((x) & (-x))
const int MAX=8;
vector<int> a(MAX+1,0);
vector<int> BITree(MAX+1,0); //前缀和
void Update(int id,int new_data){ //维护数据
int temp=id;
int increse=new_data-a[id]; //获取修改结点的增量
while(temp<=MAX){
BITree[temp]+=increse; //对每个父节点都要修改增量
temp+=lowbits(temp); //向前反推父节点直到根节点停止
}
}
int GetSum(int id){ //前缀和
int sum=0; int temp_id=id;
while(temp_id>0){
sum+=BITree[temp_id];
temp_id-=lowbits(temp_id);
}
return sum;
}
int main(void){
for(int i=1;i<=MAX;i++)
Update(i,i);
printf("区间[2,6]的和:%d",GetSum(6)-GetSum(2-1)); //求SubArr=GetSum[j]-GetSum[i-1]
}
创建BITree数组可以调用Updata函数
使用树状数组求序列的逆序对
树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0。从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是总的逆序对数。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[500005],b[500005],n;
//a是原序列,b是树状数组,当a[]数组元素值很大时,b数组开的很大
//假如a[i]的最大值是2100000000,那么b数组就得开b[2100000000+7]
//超出范围,需要离散化
int lowbit(int x){
return x&(-x);
}
void add(int x){
while(x<500005){
b[x]++;
x+=lowbit(x);
}
}
int getsum(int x){
long long sum=0;
while(x>0){
sum+=b[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
long long n,i,ans;
while(cin>>n){//n为数的总数.
ans=0;
memset(b,0,sizeof(b));//给b数组赋初值
/* 顺着扫描原序列
*/
for(i=1;i<=n;i++)
cin>>a[i];
//倒序扫描原序列
for(i=n;i>=1;i--){
add(a[i]);
ans+=getsum(a[i]-1);//统计出比a[i]小的数的个数,只不过是用树状数组统计
}
cout<<ans<<endl;
}
}