一 定义
树状数组是一种数据结构,支持区间内的查询,单点修改,区间修改等的一种数据结构,虽然支持的功能较线段树较少,但是它具有代码量少,逻辑清晰等优势
二 原理
对于树状数组,首先我们有一个原数组a[30], 然后我们有一个BIT数组tree[30],对于每一个数字,我们都能得到它的二进制表达,基于这个二进制表示,每个数都负责了一个区间内的数,如tree[4]负责的是1 2 3 4 四个数的区间,tree[3] 负责的是 3 这个数。
三 代码实现
l o w b i t ( x ) 返 回 的 是 x 中 最 近 的 一 个 1 lowbit(x)返回的是x中最近的一个1 lowbit(x)返回的是x中最近的一个1
inline ll lowbit (ll x)
{
return x & -x;
}
u p d a t e ( x ) 是 对 x 这 个 位 置 上 的 数 进 行 修 改 update(x)是对x这个位置上的数进行修改 update(x)是对x这个位置上的数进行修改
inline void update(ll x,int p)
{
for (ll i = x; i <= n; i += lowbit(i))
tree[i] += p;
}
f i n d ( x ) 寻 找 的 是 这 个 位 置 到 之 前 的 数 的 区 间 内 的 所 有 和 find(x)寻找的是这个位置到之前的数的区间内的所有和 find(x)寻找的是这个位置到之前的数的区间内的所有和
inline int find(ll x)
{
int sum = 0;
for (ll i = x; i > 0; i -= lowbit(i))
sum += tree[i];
return sum;
}
四 逆序对
模版题 逆序对其实就是求在一一个数组内,有多少组数字,满足序列的大小关系和数字的大小关系是相反的。
1.解题思路
首先我们对一个这个数组进行离散话,将里面的数字之间的大小关系转化为相对的大小关系,然后再对他按照大小的顺序进行排列,然后再这个大小的顺序,将每一个数的序号存入这个树状数组内,更新树状数组内比这个数大的数之和。当我们进行find操作时,得到的是比这个数小的数的数目之和。所以i - find(x)得到的是这个数字的逆序对的数目,从1 ~ n求和即可
2 代码
#include<iostream>
#define N 500
#define ll long long
using namespace std;
ll bit[N],Rank[N],ans,n;
struct point
{
int num;
int value;
}f[N];
ll lowbit(ll x){return x&-x;}
inline void update(ll num,ll i)
{
for(;num <= n;num+=lowbit(num)) bit[num]+=i;
}
inline int cmp(point a, point b)
{
if(a.value==b.value) return a.num < b.num;
else return a.value < b.value;
}
inline ll ask(ll p)
{
ll sum = 0;
for(;p;p-=lowbit(p))sum+=bit[p];
return sum;
}
int main()
{
scanf("%lld",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d",&f[i].value);
f[i].num = i;
}
sort(f+1,f+1+n,cmp);
for(ll i = 1;i<= n;i++) Rank[f[i].num] = i;
for(int i=1;i<=n;i++)
{
update(Rank[i],1);
ans+=i-ask(Rank[i]);
}
printf("%lld",ans);
return 0;
}