定义三个数组:
求逆序数时 : tree只在中间过程有用
求前缀和 , 区间和 : tree储存 ~lowbit( i ) 的总和
lowbit( i ) 函数的作用是取二进制最右边的 1
const int maxn = (n + 5); n 为数据范围
int a[maxn] , p[maxn] , tree[maxn];
a 储存原数组
p 储存原数组的下标
tree 构造树形结构
输入 原数组 , 下标数组 和 tree数组的初始:
void Read(){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> a[i] , p[a[i]] = i;
}
单点跟新:对 tree 中的值进行修改操作
求前缀 和 区间和的修改过程
void updata(int ide , int up){
while(ide <= n) tree[ide] += up , ide += ide & (-ide);
}
求逆序数的修改过程
void change(int ide){
while(ide <= n) tree[ide] ++ , ide += ide & (-ide);
}
查 询:对 tree 中的数值进行查询操作
int query(int ide){
int s = 0;
while(ide) s += tree[ide] , ide -= ide & (-ide);
return s;
}
Work函数:
求逆序数 (sum)
void Work(){
for(int i = n;i >= 1;-- i){
sum += query(a[i]); //如果存在 0 ,则将a[i]改成a[i] + 1
change(a[i]); //如果存在 0 ,则将a[i]改成a[i] + 1
}
}
求前缀和
void Work(){
for(int i = 1;i <= n;-- i){
updata(i , a[i]);
}
cout << query(n) << endl;
//区间修改
//updata(l , val) , updata(r + 1 , - val);
}
求 逆序数 时万一 a[ i ] 远远大于 n 或者 存在相同的元素 , 则进行离散化:
int b[100000];
离散化函数
bool cmp(int x , int y){
if(a[x] == a[y]) return x > y;
return a[x] > a[y];
}
修改读取数组为:
void Read(){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> a[i] , b[i] = i;
}
计算逆序数的work函数改为:
void Work(){
sort(b + 1 , b + 1 + n , cmp); //离散化
for(int i = 1;i <= n;++ i){
change(b[i]);
sum += query(b[i] - 1);
}
}
离散化的实际作用就是将原数组改成 -> 大小顺序的数组
eg: 99999 1 5 3 2 离散化后的结果为: 5 1 4 3 2