Day2 T4求逆序對(樹狀陣列 歸併排序)

2022-05-14 20:57:55 字數 1736 閱讀 1338

a[i]為字首和

推導 (a[j]-a[i])/(j-i)>=m

a[j]-a[i]>=m(j-i)

a[j]-m*j>=a[i]-m*i

設b=a-m*();

b[j]>=b[i]

也就是求逆序對;

求逆序對的方法主要有兩種:

歸併排序;

樹狀陣列;

這裡兩種方法都學習一下:

1.之前對於樹狀陣列的印象就只有單點修改和區間求和

一直覺得lowbit是乙個神奇的東西(至今沒有搞懂原理)

上網搜了一下用樹狀陣列求逆序對的方法,發現有乙個大神寫的很棒....看得很明白(感謝~~)

順便學了一下離散化,也就是文中的:

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

sort(in+1,in+n+1,cmp);

for(i=1;i<=n;i++) aa[in[i].order]=i;

有點像指標操作。(自己對離散化的初步感受是這樣的)

然後就是根據樹狀陣列的原理求逆序對了

其實一直不是很清楚樹狀陣列的原理,翻了翻書才有一點點的領悟吧

1).首先是update中的c陣列的理解,上面鏈結的那個資料中解釋的過程會誤以為c是統計某個數的個數的

仔細看白書會發現其實並不是這樣,c陣列是用來維護某一區間的區間和的

getsum的操作也就是把沿途中的長條所表示的區間和加起來,這樣可以節省時間(注意理解圖)

2).具體的,標程中的c是用來記錄在某個區間裡有多少個數比i小

3).理解lowbit的過程,同樣需要仔細回看白書的解釋

無論是i=t-n;i+=lowbit(i)或是i-=lowbit(i)都是乙個找父親的過程

4).其實說白了lowbit到底有什麼用呢,其實也就是節省了時間,做到快速簡便而已吧

嗯...這樣的話,對於樹狀陣列的原理算是搞懂了qaq感覺這種東西很容易忘記怎麼辦?

給以後的自己乙個忠告唄~先看白書,好好理解圖,再看自己的感悟,最後看鏈結資料;

2.另一種方法就是很傳統的用:歸併排序求逆序對

這種演算法求逆序對也很容易理解,簡單的說也無非就是基於快排思想+統計個數

主要的程式:p版的...不要在意這些細節...

procedure mergesort(l,r:longint);

var mid,i,j,k:longint;

begin

if l=r then exit;

mid:=(l+r) div 2;

mergesort(l,mid);

mergesort(mid+1,r);

i:=l;j:=mid+1;k:=l;

while (i<=mid) and (j<=r) do

if v[i]v[i]那麼v[j..r]都會大於//v[i]這和求逆序對有異曲同工之妙

endelse

push(k,j);

while i<=mid do push(k,i);

while j<=r do push(k,j);

for i:=l to r do v[i]:=temp[i];

end;

根據推導建立等式,之後輸出ans即可

很好理解就不多說了...

晚安民那

樹狀陣列求逆序對

題目描述 給定乙個陣列a,它包含n個整數,分別是a 1 a 2 a n 如果存在下標i和j,使得 i j 且 a i a j 同時成立,則 i,j 就為乙個 逆序對 那麼a陣列總共有多少對不同的 逆序對 輸入格式 1247.in 第一行為n 1 n 100000 接下來是n行,每行乙個長整型範圍內的...

樹狀陣列求逆序對

很久以前就學了樹狀陣列,也知道可以用來求逆序對,然而一直沒弄明白他是怎麼實現的 可能當時沒搞清楚逆序對是什麼吧。逆序對就是如果i j a i a j 這兩個就算一對逆序對,簡單來說,所有逆序對的個數和就是找每乙個數的前面有幾個比他的大的數,他們加起來的和就是逆序對的總數。知道什麼是逆序對後就好辦了,...

樹狀陣列 求逆序對

樹狀陣列可以解決線段樹能夠解決的問題,且更加節省空間。線段樹的講解 可以看這位大佬的部落格 樹狀陣列的講解 另一位大佬的部落格 這裡主要寫一下利用樹狀陣列來求解逆序對的個數。簡單來說就是一段序列裡面每個數所在位置之前的位置上比這個數大的數字個數之和。例如 1 2 3 5 4 只有 4 前面的 有乙個...