逆序對 線段樹&樹狀數組

來源:互聯網
上載者:User

標籤:style   直接   分享   hdu   syn   log   技術   逆序   pre   

 

17年的時候在HDU新生賽的時候遇到這樣一道題目, 當時對於這種題目, 只會n^2去數左邊比他大的個數 再相加一下 就是答案了。

無奈n是1e5 毫無疑問的T了。 後來學長說這個不就是歸併排序嗎, 你去學一下歸併就可以做了, 然後我去學了歸併, 又交了一發,

結果竟然還是T(這Y的不是耍我玩嗎)。 然後從另一位學長哪裡聽說了用線段樹去求逆序對, 把n^2變成nlogn就不會T了,最後,

我又學了線段樹,終於這回AC了。寫這個文章的時候,我順便去HDU找了找這道題目,結果找不到這道題目,竟然沒掛出來。。。。

慶幸的是當時比較勤奮,打完新生賽沒幾天就補上了,不然就沒機會做這道題目了。

好了 廢話不多說 我們先上一個n^2的數數演算法。

 1 int main() 2 { 3     int n; 4     while(cin >> n) 5     { 6         ans = 0; 7         for(int i = 1; i <= n; i++) 8         { 9             cin >> a[i];10             if(i%2==0 && a[i-1]>a[i])11             {12                 swap(a[i-1],a[i]);13                 ans++;14             }15         }16         for(int i = 1; i <= n; i+=2)17         {18             for(int j = 1; j < i; j+=2)19             {20                 if(a[j] > a[i]) ans++;21             }22         }23         cout << ans << endl;24     }25     return 0;26 }

n^2演算法就是數一下前面有多少個數比現在這個數大 這樣全部跑完只後就是逆序數了。

其中重點是 前面有多少個數比現在這個數大 

但是每次從1for一遍到i的位置太浪費時間了 

所以我們用線段樹來最佳化這個數數過程

 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 #define ll long long 6 const int N=100005; 7 int sum[N<<2], a[N]; 8 ll ans; 9 void Update(int c, int l, int r,int rt)10 {11     if(l == r)12     {13         sum[rt]++;14         return;15     }16     int m = l+r >> 1;17     if(c <= m) Update(c,lson);18     else Update(c,rson);19     sum[rt]=sum[rt<<1]+sum[rt<<1|1];20 }21 ll Query(int L, int R, int l, int r, int rt)22 {23     if(L <= l && r <= R)24         return sum[rt];25     int m = l+r >> 1;26     ll cnt = 0;27     if(L <= m) cnt+=Query(L,R,lson);28     if(m < R) cnt += Query(L,R,rson);29     return cnt;30 }31 int main()32 {33     ios::sync_with_stdio(false);34     cin.tie(0);35     int n;36     while(cin >> n)37     {38         ans = 0;39         memset(sum, 0, sizeof(sum));40         for(int i = 1; i <= n; i++)41         {42             cin >> a[i];43             if(i%2==0 && a[i-1]>a[i])44             {45                 swap(a[i-1],a[i]);46                 ans++;47             }48         }49         for(int i = 1; i <= n; i+=2)50         {51             ans+=Query(a[i],n,1,n,1);52             Update(a[i],1,n,1);53         }54         cout <<ans << endl;55     }56     return 0;57 }

線段樹演算法的精髓就是將出現過的數對應的位置標記一下(+1)

假設 i=k時, 查詢一下區間  [a[k], n] 的區間和, 這個和就是(j < k && a[j] > a[k])  的數目

然後在a[k] 的位置 +1 

重複這個過程就能求出解了

 

是不是很疑惑為什嗎?

當查詢區間的時候, 如果在後面的區間內查詢到次數不為0時, 說明有幾個比他大數在他前面出現過,

線段樹寫法的精髓就是標記位置 進行查詢, 這就是線段樹的寫法。

 

當然還有樹狀數組的寫法

 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100005; 4 int sum[N], a[N]; 5 int n; 6 int lowbit(int x) 7 { 8     return x&(-x); 9 }10 void Update(int x)11 {12     while(x <= n)13     {14         sum[x]++;15         x += lowbit(x);16     }17 }18 int Query(int x)19 {20     int ans = 0;21     while(x > 0)22     {23         ans += sum[x];24         x -= lowbit(x);25     }26     return ans;27 }28 int main()29 {30     ios::sync_with_stdio(false);31     cin.tie(0);32     while(cin >> n)33     {34         long long  ans = 0;35         memset(sum, 0, sizeof(sum));36         for(int i = 1; i <= n; i++)37         {38             cin >> a[i];39             if(i%2==0 && a[i-1]>a[i])40             {41                 swap(a[i-1],a[i]);42                 ans++;43             }44         }45         for(int i = 1; i <= n; i+=2)46         {47             ans += Query(n) - Query(a[i]);48             Update(a[i]);49         }50         cout << ans << endl;51     }52     return 0;53 }

注意的是 線段樹與樹狀數組求逆序對的時候 數值不能太大 比如a[i] <= 1e9的時候 就不能直接用樹狀數組和逆序數去求了,因為開不了那麼大的空間。

但在這個時候 如果n不是很大 可以先對資料進行離散化 進行樹狀數組或者線段樹處理資料。

PS: 本篇部落格到這裡就結束了,謝謝你的觀看, 如果有疑惑可以在下方留言或者加我QQ:1073223357進行詢問。

    同時歡迎各路大牛對我代碼中的漏洞進行指正。

 

逆序對 線段樹&樹狀數組

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.