树状数组求 逆序数 前缀和

定义三个数组

求逆序数时 : 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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值