樹狀數組求逆序對


對於數的范圍比較小,我們可以這樣來求解逆序對。

樹狀數組b[val]表示的是val在數組中出現的次數。

我們倒序掃描原數組a,對於位置i,由於樹狀數組里面保存的是val出現的次數,我們先用樹狀數組求出當前樹狀數組中比a[i]這個值小的元素的個數,由於是倒序掃描,之前加入樹狀數組中的數的位置都在i后面,因此我們就把求得的比a[i]這個值小的元素的個數累加到答案中。

for(int i=n;i;i--)
{
     ans+=ask(a[i]-1);  
     add(a[i],1);  
}

這是針對數的范圍較小采取的方法,當數的范圍較大時,我們對數據經行排序,然后離散化。下面給出一種求解方法。

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 5e5 + 10;
typedef long long ll;
#define lowbit(x) (x&(-x))
int n, m, c[N], a[N], b[N];
void add(int x)
{
    for (; x <= n; x += lowbit(x))
        c[x]++;
}
 int ask(int x)
{
    int s = 0;
    for (; x > 0; x -= lowbit(x))
        //cout << x <<" "<< c[x] << endl;
        s += c[x];
    return s;
}
bool cmp1(const int x, const int y)
{
    if (b[x] == b[y]) return x > y;//這個要注意,一定要讓大的跑前面,不然就會多統計
    return b[x]>b[y];
}
int main()
{
    scanf("%d", &n);
    ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &b[i]);
        a[i] = i;
    }
    sort(a + 1, a + n + 1, cmp1);
    for (int i = 1; i <= n; i++)
    {
        add(a[i]);
        ans += 1LL * ask(a[i] - 1);//之前加入數狀數組的元素都比當前元素值大,因此我們查詢下標比當前小的個數,累加答案
    }
    printf("%lld\n", ans);
    return 0;
}

這種情況需要先排序,那還不如直接用歸並排序求。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM