poj3321—Apple Tree

來源:互聯網
上載者:User
 題目大意:

給你一顆蘋果樹,樹的主幹設為1,每一個分支設為一個數,一直到N,代表這顆蘋果樹。每個分支上面只能最多有一個蘋果,也就是一個枝子上面不可能有兩個蘋果,另外注意一點,不要把蘋果樹想象成二叉樹,蘋果樹每個節點可以分出很多叉,應該是多叉樹。

 

輸入是叉之間的關係,

1 2

1 3

就是主幹上面兩個叉分別是2 和3.

 

下面是兩種操作,Q 和C

C   j  的意思是如果 j 這個枝子上面有蘋果就摘下來,如果沒有,那麼就會長出新的一個

Q  j  就是問 j 這個叉上面的蘋果總數。

 

這個題很明顯是線段樹,其實我很多時候就用樹狀數組解決,但是,這個數組怎麼來定?????演算法很容易搞定,但是初始化是問題。

先來說一下樹狀數組:

 

先看一個例題:

數列操作:

給定一個初始值都為0的序列,動態地修改一些位置上的數字,加上一個數,減去一個數,或者乘上一個數,然後動態地提出問題,問題的形式是求出一段數位和.

若要維護的序列範圍是0..5,先構造下面的一棵線段樹:

 

 

 

可以看出,這棵樹的構造用二分便可以實現.複雜度是2*N.

每個結點用數組a來表示該結點所表示範圍內的資料之和.

修改一個位置上數位值,就是修改一個葉子結點的值,而當程式由葉子結點返回根節點的同時順便修改掉路徑上的結點的a數組的值. 

對於詢問的回答,可以直接尋找i..j範圍內的值,遇到分叉時就兵分兩路,最後在合起來.也可以先找出0..i-1的值和0..j的值,兩個值減一減就行了.後者的實際操作次數比前者小一些.

這樣修改與維護的複雜度是logN.詢問的複雜度也是logN,對於M次詢問,複雜度是MlogN.

然而不難發現,線段樹的編程複雜度大,空間複雜度大,時間效率也不高.

更好的解決辦法就是用樹狀數組!

中的C數組就是樹狀數組,a數組是原數組

 

 

 

 

對於序列a,我們設一個數組C定義C[i] = a[i-2^k+1] + a[i-2^k+2] + … + a[i],k為i在二進位下末尾0的個數。

2^k的計算可以這樣:2^k = i & (i^(i-1)) 

inline int Lowbit(int x){       // 求x最低位1的權       return x & (x^(x-1));}定義C[i] = a[i-2^k+1]+a[i-2^k+2]+...+a[i];若要修改 a[k]的值,則C數組的修改過程如下:(n為C數組的大小)void Change(int k, int delta){       while( k<=n ){              C[k] += delta;              k += LowBit(k);       }}求a中1..k元素的和int Getsum(int k){       int ret = 0;       while( k>0 ){              ret += C[k];              k -= Lowbit(k);       }       return ret;}

 

若要求i..j的元素和的值,則求出 1~i-1和1~j的值,相減即可

在很多的情況下,線段樹都可以用樹狀數組實現.凡是能用樹狀數組的一定能用線段樹.當題目不滿足減法原則的時候,就只能用線段樹,不能用樹狀數組.例如數列操作如果讓我們求出一段數字中最大或者最小的數字,就不能用樹狀數組了.

註:用數組儲存靜態一維線段數也可以不記錄左右孩子的下標

如0號是根節點,其孩子是1、2;

1號的孩子是3、4;

2號的孩子是5、6;

3號的孩子是7、8;

……

n號的孩子是2*n+1、2*n+2。

再說說本題如何用樹狀數組來解決:

 

想必大家都明白上面說的了吧,就是為了快速的查詢一個數組某一段的和,一旦這一段經過修改,依然快速給出答案。

而這個題不正是這個意思麼,原先都是一個蘋果,摘掉或者新長出,不就是改變數組的某個值麼,這時候要查詢的不就是某個區間的值嗎?

 

而上面的例子就是一個一維數組,但是現在如何把一個樹轉化為一維數組呢?這是這道題目的關鍵,否則沒法做。

如果理解了這一點,就好辦了。

對一棵樹進行深搜,然後將深搜的順序重新標上號,然後放到一個數組中,記下每一個枝子得起始點和終結點,然後就可以用樹狀數組了。

還是舉個例子吧。。。

如果一棵蘋果樹是這樣的。

 

那麼我們知道1是主幹。。。。

深搜的順序是1 4 6 5 7 2 3 當然這也是根據題目的輸入建的廣義表。

那麼當我們深搜的時候就可以在下面標上:

1 4 6 5 7 2 3 (廣義表裡面的東西,深搜結果)

1 2 3 4 5 6 7(num數組我們求和要用的)

這樣不就是樹狀數組了麼。

我們用start【1】= 1 end【1】=7代表1以上的樹枝為1-7,也就是所有

用 start【2】= 6  end【2】 = 7 代表2以上的樹枝是 3

同理

start【4】=2 end【4】 = 5 這樣我們就知道4上面的樹枝了

每一個樹枝在num【n】總數組中的位置,這樣我們就可以計算啦。。。樹狀數組,和上面將的一樣了,成功轉換

具體鍵代碼,main函數主要建廣義表,dfs主要是找到每一個樹枝在num【n】數組中的起點和終點並記錄在start和end數組中。

這樣下面就是樹狀數組的三個函數。

有人會問,為什麼要+ 或者-  x & (x^(x-1)),這個我們可以看上面的規律,具體起源於什麼,我也不知道,根據上面講的就是這個數的二進位從右邊第一個1的位置。

如果還不是很明白,請回複,我會的盡量解釋,謝謝。

代碼:
#include <iostream>#include <cstdio>using namespace std;int n, m;int inc = 0;int num[100001];int start[100001];int end[100001];//要用到的廣義表的結構struct TREE {int data;TREE * next;};TREE tree[100001];void dfs(int pos){int i, j, k;start[pos] = ++ inc;TREE *p = tree[pos].next;while (p){if (start[p->data] == 0){dfs(p->data);}p = p->next;}end[pos] = inc;}//中間用到的規律值int lowBit(int x){return x&(x^(x-1));}//求從開始到這裡的和int sSum(int end){int sum = 0;while (end > 0){sum += num[end];end -= lowBit(end);}return sum;}//更新自己並且和自己相關的void change(int pos, int tmp){while (pos <= n){num[pos] += tmp;pos += lowBit(pos);}}int main(){int j,k,s,t;scanf("%d", &n);for (int i = 1; i < n; i ++){//每一個點都建一個長長的鏈表,表示自己的一個分支scanf("%d%d", &s, &t);TREE *p = new TREE;p->data = t;p->next = tree[s].next;tree[s].next = p;TREE *q = new TREE;q->data = s;q->next = tree[t].next;tree[t].next = q;}//映射到樹狀數組dfs(1);//每個初始化有一個蘋果for (int i = 1; i <= n; i ++){change(i, 1);}char ch;scanf("%d", &m);for (int i = 0; i < m; i ++){getchar();scanf("%c%d", &ch, &j);if (ch == 'C'){int sum = sSum(start[j]);sum -= sSum(start[j] - 1);if (sum == 1){change(start[j], -1);}else{change(start[j], 1);}}else{int sum = sSum(end[j]);sum -= sSum(start[j] - 1);printf("%d\n", sum);}}return 0;}

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.