• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            ACM___________________________

            ______________白白の屋
            posts - 182, comments - 102, trackbacks - 0, articles - 0
            <2010年8月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            常用鏈接

            留言簿(24)

            隨筆分類(332)

            隨筆檔案(182)

            FRIENDS

            搜索

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            樹狀數組 小結

            Posted on 2010-08-25 20:19 MiYu 閱讀(761) 評論(0)  編輯 收藏 引用 所屬分類: ACM_資料 、ACM ( 樹狀數組 )

            今天學習了 樹狀數組, 自己小結下 :

             

            簡單介紹下 樹狀數組 :

                    樹狀數組是一個查詢和修改復雜度都為log(n)的數據結構,假設數組a[1...n],那么查詢a[1] + …… + a[i] 的時間是log級別的,而且是一個在線的數據結構,支持隨時修改某個元素的值,復雜度也為log級別。

             

            來觀察一下這個圖:

             


             

            令這棵樹的結點編號為C1C2……Cn。令每個結點的值為這棵樹的值的總和,那么容易發現:

            C1 = A1

            C2 = A1 + A2

            C3 = A3

            C4 = A1 + A2 + A3 + A4

            C5 = A5

            C6 = A5 + A6

            C7 = A7

            C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

            ……

            C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16

             

            這里有一個有趣的性質,下午推了一下發現:

            設節點編號為x,那么這個節點管轄的區間為2^k(其中kx二進制末尾0的個數)個元素。因為這個區間最后一個元素必然為Ax,所以很明顯:

            Cn = A(n – 2^k + 1) + …… + An

            算這個2^k有一個快捷的辦法,定義一個函數如下即可:

            int lowbit(int x){

            return x & (x ^ (x – 1));

            }

             

            當想要查詢一個SUM(n)時,可以依據如下算法即可:

            step1: 令sum = 0,轉第二步;

            step2: 假如n <= 0,算法結束,返回sum值,否則sum = sum + Cn,轉第三步;

            step3:  n = n – lowbit(n),轉第二步。

             

            可以看出,這個算法就是將這一個個區間的和全部加起來,為什么是效率是log(n)的呢?以下給出證明:

            n = n – lowbit(n)這一步實際上等價于將n的二進制的最后一個1減去。而n的二進制里最多有log(n)1,所以查詢效率是log(n)的。

             

            那么修改呢,修改一個節點,必須修改其所有祖先,最壞情況下為修改第一個元素,最多有log(n)的祖先。所以修改算法如下(給某個結點i加上x):

            step1: i > n時,算法結束,否則轉第二步;

            step2: Ci = Ci + x, i = i + lowbit(i)轉第一步。

             

            i = i +lowbit(i)這個過程實際上也只是一個把末尾1補為0的過程。

            //修改過程必須滿足減法規則!

             

            所以整個程序如下:

            const int MAX = 50000;

            #define lowbit(x) ((x)&(-x))

            int com[ MAX + 1 ],N,T;

            void modify ( int pos, int val ){

                 while ( pos <= N ){

                        com[pos] += val;

                        pos = pos + lowbit(pos);  

                 } 

            }

            int quy ( int x ){

                int sum = 0;

                while ( x > 0 ){

                       sum = sum + com[x];

                       x = x - lowbit(x);

                } 

                return sum;

            }

            初始化 :     for ( int i = 1; i <= N; ++ i ){

                                   scanf ( "%d",&x );

                                   modify ( i, x ); 

                             } 

            ------------------------------------------------------------------------------------

            為什么要用樹狀數組 ?

             

            原因如下: 

             

            |  1. 首先我們得知道一個問題,那就是線段樹得作用并

             

            不只是用來存儲線段的,也可以存儲點的值等等.  


            |  2. 對于靜態的線段樹,空間上需要的數組有:當前結點

             

            的數據值,左兒子編號,右兒子編號.至少這么三個數組

             

                3. | 而在時間上雖然是NlogN的復雜度,但是系數很大.|

             

              4. 實現起來的時候編程復雜度大,空間復雜度大,時間

             

            效率也不是很理想

             

             

             

             

             

             所以這個時候樹狀數組成了一個很好的選擇.

             

            先看一個例題:

             

            數列操作:

             

                給定一個初始值都為0的序列,動態地修改一些 

             

            位置上的數字,加上一個數,減去一個數,或者乘上

             

            一個數,然后動態地提出問題,問題的形式是求出

             

            一段數字的和. 

             

             

            如果直接用樸素方法做的話,修改的復雜度是O(1), 

             

            詢問的復雜度是O(N),M次詢問的復雜度是M*N.

             

            M,N的范圍可以有100000以上!!!!

             

             

             

             有沒有更好的方法???

             

             

             

             呵呵, 肯定有啦, 就是我要說的樹狀數組!!!  

             

            具體的樹狀數組的解釋請看上面,  那么這個2k怎么求? 是怎么

             

            來的?  

             

            K的計算可以這樣:

             

            |2k=x and (x & (x-1))

             

            |6為例

             

            |                (6)10=(0110)2

             

            |xor    6-1=(5)10=(0101)2

             

            |                         (0011)2

             

            |and          (6)10=(0110)2

             

            |                         (0010)2

             

            所以: 

             

            由數字的機器碼可以更簡單的優化成:  x & (-x)

             

            對于上面那一題,每次修改與詢問都是對C數組做處理.

             

            空間復雜度有3N降為N,時間效率也有所提高.編程復雜

             

            度更是降了不少.

             

             

             

             

             

             

             

            久久www免费人成精品香蕉| 91久久九九无码成人网站| 久久五月精品中文字幕| 久久人人爽人人爽人人片AV麻豆| 伊人久久大香线蕉综合网站| 日韩人妻无码一区二区三区久久99 | 久久婷婷成人综合色综合| 亚洲午夜精品久久久久久浪潮| 国产激情久久久久久熟女老人| 91久久精一区二区三区大全| 久久天天躁狠狠躁夜夜2020| 久久精品九九亚洲精品| 国产精品免费久久| 久久人爽人人爽人人片AV| 免费一级欧美大片久久网| 国产精品久久久久久久久鸭| 无码人妻久久一区二区三区蜜桃| 久久久九九有精品国产| 人人狠狠综合久久88成人| 久久成人永久免费播放| 国产精品一区二区久久国产| 亚洲精品99久久久久中文字幕| 国产精品99久久精品| 久久天天躁狠狠躁夜夜avapp| 久久精品国产亚洲Aⅴ香蕉| av国内精品久久久久影院| 久久久久久亚洲精品影院| 久久久久人妻一区精品果冻| 久久免费精品视频| 国产欧美久久一区二区| 精品久久人妻av中文字幕| 久久精品免费一区二区| 一本色道久久88综合日韩精品 | 青青草国产97免久久费观看| 久久免费视频观看| 青青草原综合久久大伊人精品| 久久婷婷国产综合精品| 久久久无码精品亚洲日韩蜜臀浪潮| 亚洲人AV永久一区二区三区久久| 久久人妻少妇嫩草AV蜜桃| 国内精品伊人久久久久网站|