码迷,mamicode.com
首页 > 编程语言 > 详细

树状数组

时间:2021-02-27 13:27:43      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:范围查询   include   ons   one   ace   syn   否则   std   ble   

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<ll> vll;
const int INF = 0x3f3f3f3f;
const long long LLINF = 4e18;
const double EPS = 1e-9;
const int maxn = 1e6 + 10;

#define LSOne(S) ((S) & -(S))  //不加括号会导致结果出错,具体原因见P45
int n;
int ft[maxn], ft_extra[maxn];  //ft数组用于存储一个传统的树,ft_extra数组用于区间修改+区间查询时存储的另一颗树
int f[maxn];                   //f数组用于存放题目输入的数据或输入数据的差分数组
int a[maxn];

ll rsq(ll i) {                 //求f[1]到f[i]的和,若f为差分数组则此功能为 point_query单点查询f[i]
    ll sum = 0;
    for (; i; i -= LSOne(i)) sum += ft[i];  //从后往前加,每次减去一个 LSOne(i)(二进制截取最后一位1)
    return sum;
}

ll pq_range(ll n) {            //用于计算(n+1)f[i] - i*f[i] 的前n项和
    ll sum = 0;
    for (int i = n; i; i -= LSOne(i)) sum += (n + 1) * ft[i] - ft_extra[i];
    return sum;
}

ll rsq_range(ll l, ll r) {     //range_query 范围查询,习惯上用l作为左端点,r作为右端点, f必须为差分数组
    return pq_range(r) - pq_range(l - 1);
}

void update(int i, ll v) {                //单点更新
    for (; i <= n; i += LSOne(i)) {       //从前往后更新,所有受到影响的点都要更新一遍
        ft[i] += v;
        ft_extra[i] += i * v;  //需要进行区间修改和区间查询的时候才需要这一步
    }
}

void range_update(int l, int r, ll v) {   //区间更新,[l,r]内所有数 +v
    update(l, v);
    update(r + 1, -v);
}

void build() {                 //建树,复杂度O(n)
    for (int i = 1; i <= n; i++) {
        ft[i] += f[i];
        ft_extra[i] += i * f[i];
        int x = i + LSOne(i);
        if (x <= n) {         //如果存在父节点,顺便把父节点也更新了
            ft[x] += ft[i];
            ft_extra[x] += ft_extra[i];
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;

    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        f[i] = a[i] - a[i - 1];  //将f建立为输入数据的差分数组
    }
    cout << "input:" << endl;
    for (int i = 1; i <= n; i++) cout << f[i] << " ";
    cout << endl;
    build();
    for (int i = 1; i <= n; i++) cout << ft[i] << " ";
    cout << endl;
    cout << "data of [2...4] +2" << endl;
    range_update(2, 4, 2);
    for (int i = 1; i <= n; i++) cout << ft[i] << " ";
    cout << endl;
    cout << "若f为差分数组则单点查询f(3),否则计算f[1..3]的和:" << endl;
    cout << rsq(3) << endl;
    cout << "Query sum of data of[1...3]:" << endl;
    cout << rsq_range(1, 3) << endl;
    return 0;
}

树状数组

标签:范围查询   include   ons   one   ace   syn   否则   std   ble   

原文地址:https://www.cnblogs.com/xiezeju/p/14454748.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!