線段樹 求逆序數

2021-06-22 18:31:40 字數 2222 閱讀 3420

hdu1394 minimum inversion number

題意:求inversion後的最小逆序數

思路:用o(nlogn)複雜度求出最初逆序數後,就可以用o(1)的複雜度分別遞推出其他解

線段樹功能:update:單點增減 query:區間求和

逆序數: 對於

n個不同

的元素,先規定各元素之間有乙個標準次序(例如n個 不同的自然數,可規定從小到大為標準次序),於是在這n個元素的任一排列中,當某兩個元素的先後次序與標準次序不同時,就說有1個逆序。乙個排列中所有逆序總數叫做這個排列的逆序數

在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個

逆序。乙個排列中逆序的總數就稱為這個排列的

逆序數。逆序數為

偶數的排列稱為

偶排列;逆序數為奇數的排列稱為

奇排列。如2431中,21,43,41,31是逆序,逆序數是4,為偶排列。

首先,求逆序數對的思路:

1.得到整個數列後,從前往後掃,統計比a[i]小的,在a[i]後面的有多少個

這樣做的話,應該是只有n2的暴力作法

2.統計a[i]前面的且比它大的數

這樣做的話,就可以利用輸入的時效性,

統計比這個數大的數的num和,

然後把把這個和加到總逆序數sum裡。

這樣做的話直接的暴力作法依然是n2,但是,

我們可以在,

統計比這個數大的數的num和這一步進行優化,利用線段樹求區間域值的複雜度是logn,

所以總體複雜度就降到了nlogn。

再來看這道題,求得初始數列的逆序數後,再求其他排列的逆序數有乙個規律,就是

sum = sum + (n - 1 - a[i]) - a[i];

這個自行驗證吧,相信很容易得出

最後,拓展一下,如果要求正序數怎麼辦?很簡單,無非是大小調一下

再問,如果要求滿足ia[j]>a[k]的數對總數怎麼辦?

可以從中間的這個數入手,統計a[i]>a[j]的對數m,以及a[j]>a[k]的對數n,m*n就是。。。

要求a[i]>a[j]的個數還是一樣的,那麼a[j]>a[k]的個數呢?

兩種思路:

1.得到a[i]>a[j]的對數後,將數列倒過來後再求a[j]2.更簡單的做法是,找到規律發現,n = 整個數列中比a[j]小的數 — 在a[j]前面已經出現的比a[j]小的數的個數

即(假設數列是從1開始的) n = (a[j] -1) - (j - 1 - m )

本題處理:

#include #define lson l , m , rt << 1

#define rson m + 1 , r , rt << 1 | 1

const int maxn = 5555;

int a[maxn];

struct treetree[maxn<<2];

void pushup(int rt)

void build(int l,int r,int rt)

int m = (l + r) >> 1;

build(lson);

build(rson);

//pushup(rt); 這題初始化0 沒必要這步了

} void update(int p,int l,int r,int rt)

int m = (l + r) >> 1;

if (p <= m) update(p , lson);

else update(p , rson);

pushup(rt); //這步需要,

} int query(int l,int r,int l,int r,int rt)

int m = (l + r) >> 1;

int ret = 0;

if (l <= m) ret += query(l , r , lson); //找到最底部

if (r > m) ret += query(l , r , rson);

return ret;

} int main()

ans = sum;//先讓ans為初始順序的值

for(i = 1;i < n;i++){

sum = sum + (n - 1 - a[i]) - a[i];//重點步驟注意理解

ans = ans

逆序數 線段樹

既然是區間操作 我們想到了線段樹 我們先建立乙個空樹 然後呢 按照這個序列的順序將每個值插入 每次插入伴隨一次查詢 查詢前面插入的比這次插入的大的數字的個數 然後就可以了 複雜度 nlogn 可以接受 題意 就是給出一串數,當依次在將第乙個數變為最後乙個數的過程中,要你求它的最小逆序數。思路 可以用...

hdu 1394 求逆序數(線段樹求)

題意描述 給你乙個有0 n 1數字組成的序列,然後進行這樣的操作,每次將最前面乙個元素放到最後面去會得到乙個序列,那麼這樣就形成了n個序列,那麼每個序列都有乙個逆序數,找出其中最小的乙個輸出!解析 求出a1,a2,an 1,an的逆序數之後,就可以遞推求出其他序列的逆序數。假設要把a1移動到an之後...

線段樹或樹狀陣列求逆序數

線段樹或樹狀陣列求逆序數 求逆序數的方法有分治,歸併,本文只介紹線段樹或樹狀陣列求逆序數的辦法,眾所周知,線段樹和樹狀樹可以用來解決區間操作問題,就是因為這兩個演算法區間操作的時間複雜度很低o logn 才讓這種方法具有可行性。首先先來看乙個序列 6 1 2 7 3 4 8 5,此序列的逆序數為5 ...