[模板] 树状数组及其应用

树状数组


树状数组又是一个区间查询修改利器 前缀和的维护 差分的维护

又强又方便

二进制组合原理

int n, m;

ll arr[MAXN] = {0}, crr[MAXN] = {0}; //arr原数组, crr二进制下标树

int lowbit(int x)
{
	return x & -x;
}

void add(int pos, int val)
{
	for( ; pos <= n; pos += lowbit(pos))
		crr[pos] += val;
}

ll ask(int pos)
{
	ll ret = 0;

	for( ; pos; pos -= lowbit(pos))
		ret += crr[pos];

	return ret;
}

用法 1,区间查询和 [fst, lst] 

前缀和相减即可                          sum = crr[x] - crr[y - 1]

用法2 单点更新                          add(pos, val)

用法3 区间加和 [fst, lst]              add(fst, val), add(lst + 1, -val); 差分

用法4 区间加和的单点查询        ans = ask(k) + arr[k];

树状数组求逆序数


树状数组可以求前缀和,

那么设一个数组C记录当前下标的数的个数

所以从后往前扫数组可以logn的查询出当前值之后 的 比当前值小的所有数的前缀和(逆序数)

扫完再把当前值插入二进制下标树即可

当值太大的时候可以离散 这时候时间复杂度肯定就比归并要大的多了, 不过可以解决归并背不下来的情况

/*
    Zeolim - An AC a day keeps the bug away
*/

//#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
typedef long long ll;
typedef long double ld;
const int INF = 0x3f3f3f3f;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const int MAXN = 1e6 + 10;

ll arr[MAXN] = {0};
ll brr[MAXN] = {0};

ll c[MAXN] = {0};

ll rp(ll x, ll n)
{
    return lower_bound(brr, brr + n, x) - brr + 1;
}

ll lobit(ll x)
{
    return x & -x;
}

void add(ll x, ll n)
{
    for(; x <= n; x += lobit(x))
        ++c[x];
}

ll ask(ll x)
{
    ll ret = 0;

    for( ; x; x -= lobit(x))
        ret += c[x];

    return ret;
}

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);     cout.tie(0);
    //freopen("D://test.in", "r", stdin);
    //freopen("D://test.out", "w", stdout);

    int n;

    cin >> n;

    for(int i = 0; i < n; ++i)
    {
        cin >> arr[i];
    }

    memcpy(brr, arr, sizeof(arr));

    sort(brr, brr + n);

    int ln = unique(brr, brr + n) - brr;

    ll ans = 0;

    for(int i = n - 1; i >= 0; --i)
    {
        int pos = rp(arr[i], ln);

        ans += ask(pos - 1);

        add(pos, ln);
    }

    cout << ans << '\n';



    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Zeolim/article/details/89194963
今日推荐