樹(shù)狀數(shù)組求逆序?qū)υ?/h2>

歸并排序和樹(shù)狀數(shù)組都可以用nlogn的算法做到求出逆序?qū)?但這里著重講樹(shù)狀數(shù)組的原理與求法.
樹(shù)狀數(shù)組最常用的方面就是用來(lái)求逆序?qū)? 普通方法需要n^2的復(fù)雜度, 而樹(shù)狀數(shù)組只需要用nlogn的復(fù)雜度, 所以是很好的優(yōu)化, 關(guān)鍵在于內(nèi)部函數(shù)lowbit的應(yīng)用.
這是樹(shù)狀數(shù)組的結(jié)構(gòu)圖 : lowbit函數(shù)就是進(jìn)行哪些實(shí)現(xiàn)之間的轉(zhuǎn)化的, 因?yàn)檫@些數(shù)之間在二進(jìn)制中存在著某種聯(lián)系, 而lowbit函數(shù)便可把這些聯(lián)系體現(xiàn)出來(lái).!!!

image.png

總之記住樹(shù)狀數(shù)組實(shí)現(xiàn)的是nlogn的算法, 和他具體實(shí)現(xiàn)的是什么功能就行了.
當(dāng)數(shù)據(jù)的范圍較小時(shí),比如maxn=100000,那么我們可以開(kāi)一個(gè)數(shù)組c[maxn],來(lái)記錄前面數(shù)據(jù)的出現(xiàn)情況,初始化為0;當(dāng)數(shù)據(jù)a出現(xiàn)時(shí),就令c[a]=1。這樣的話(huà),欲求某個(gè)數(shù)a的逆序數(shù),只需要算出在當(dāng)前狀態(tài)下c[a+1,maxn]中有多少個(gè)1,因?yàn)檫@些位置的數(shù)在a之前出現(xiàn)且比a大。但是若每添加一個(gè)數(shù)據(jù)a時(shí),就得從a+1到 maxn搜一遍,復(fù)雜度太高了。樹(shù)狀數(shù)組卻能很好的解決這個(gè)問(wèn)題,可以把數(shù)一個(gè)個(gè)插入到樹(shù)狀數(shù)組中, 每插入一個(gè)數(shù), 統(tǒng)計(jì)比他小的數(shù)的個(gè)數(shù),對(duì)應(yīng)的逆序?yàn)?i - getsum( c[i] ),其中 i 為當(dāng)前已經(jīng)插入的數(shù)的個(gè)數(shù), getsum( c[i] )為比 c[i] 小的數(shù)的個(gè)數(shù),i- getsum( c[i] ) 即比c[i] 大的個(gè)數(shù), 即逆序的個(gè)數(shù)。最后需要把所有逆序數(shù)求和,就是在插入的過(guò)程中邊插入邊求和.

舉個(gè)例子:有5個(gè)數(shù),分別為5 3 4 2 1,當(dāng)讀入數(shù)據(jù)a=5時(shí),c為:0,0,0,0,1;d為:0,0,0,0,1;當(dāng)讀入數(shù)據(jù)a=3時(shí),c為:0,0,1,0,1;d為:0,0 , 1,1,1;當(dāng)讀入數(shù)據(jù)a=4時(shí),c為:0,0,1,1,1;d為:0,0,1,2,1;
此思想的關(guān)鍵在于,讀入數(shù)據(jù)的最大值為maxn,由于maxn較小,所以可以用數(shù)組來(lái)記錄狀態(tài)。當(dāng)maxn較大時(shí),直接開(kāi)數(shù)組顯然是不行了,這是的解決辦法就是離散化。所謂離散化,就是將連續(xù)問(wèn)題的解用一組離散要素來(lái)表征而近似求解的方法,這個(gè)定義太抽象了,還是舉個(gè)例子吧。
   假如現(xiàn)在有一些數(shù):1234 98756 123456 99999 56782,由于1234是第一小的數(shù),所以num[1]=1;依此,有num[5]=2,num[2]=3,num[4]=4,num[3]=5;這樣轉(zhuǎn)化后并不影響原來(lái)數(shù)據(jù)的相對(duì)大小關(guān)系,何樂(lè)而不為呢?。?!
還有一點(diǎn)值得注意,當(dāng)有數(shù)據(jù)0出現(xiàn)時(shí),由于0&0=0,無(wú)法更新,此時(shí)我們可以采取加一個(gè)數(shù)的方法將所有的數(shù)據(jù)都變成大于0的.

具體看代碼 : 樹(shù)狀數(shù)組+去重離散化

#include<cstdio>
#include<algorithm>
#include<cstring>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long int
#define PI acos(-1.0)
#define db double
#define mod 1000000007
using namespace std;
const int maxn=1e5+5;
const db eps=1e-6;
const int inf=1e9;
const ll INF=1e15;
int c[maxn];         //樹(shù)狀數(shù)組
int lisan[maxn];   //用來(lái)離散的存離散后的結(jié)果數(shù)組
int s[maxn];        //用來(lái)存原始狀態(tài)
int n,k;
//樹(shù)狀數(shù)組
int lowbit(int x)  //返回值最大1e5.
{
    return x&(-x);
}

void update(int i,int ans)
{
    while(i <= n){
        c[i] += ans;
        i += lowbit(i);
    }
}

int sum(int i)
{
    int s = 0;
    while(i > 0){
        s += c[i];
        i -= lowbit(i);
    }
    return s;
}
//結(jié)束
int main()
{
    while(~scanf("%d%d",&n,&k)){
        CLR(c);
        for(int i=0;i<n;i++){
            scanf("%d",&s[i]);
            lisan[i] = s[i];
        }
        sort(lisan,lisan+n);
        int len=unique(lisan,lisan+n)-lisan;
        ll res = 0;
        for(int i=0;i<n;i++){
            ll l=lower_bound(lisan,lisan+len,s[i])-lisan+1;
            update(l,1);
            res += i+1 - sum(l);
        }
        if(res < k) printf("0\n");
        else
            printf("%lld\n",res-k);
    }
}

說(shuō)一說(shuō)離散那部分.

/* 首先看題就知道肯定是需要進(jìn)行離散化的, 還有一個(gè)問(wèn)題就是可能有重?cái)?shù), 對(duì)于sort這種不穩(wěn)定排序, 不考慮
*重?cái)?shù), 是對(duì)結(jié)果又影響的, 所以需要進(jìn)行去重離散化, 一般的離散化也可以做到, 就是知道判到不重了, 就離散
* 化, 但是稍微有點(diǎn)麻煩, 所以這里就用到了, unique 和 lower_bound 函數(shù), unique是使該數(shù)組中相同的部分去
* 掉, 而lower_bound是返回第一個(gè)大于或等于x的位置, 返回的都是地址.
*/
for(int i=0;i<n;i++){
            scanf("%d",&s[i]);
            lisan[i] = s[i];
}
sort(lisan,lisan+n);       //首先排序
int len=unique(lisan,lisan+n)-lisan;   //求出離散數(shù)組的長(zhǎng)度并去重.
ll res = 0;
for(int i=0;i<n;i++){
int l=lower_bound(lisan,lisan+len,s[i])-lisan+1;    //實(shí)際上是返回的s[i] 在lisan數(shù)組中下標(biāo)位置(從1開(kāi)始) 然后
      //給原先那個(gè)數(shù)組所有相同的數(shù)都統(tǒng)一賦成一個(gè)值. 這樣就可以到達(dá)去重的目的. l 既是離散化后的結(jié)果
update(l,1);
res += i+1 - sum(l);
}

所以實(shí)際上不管離不離散化都可以用這種方法.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容