1. 程式人生 > >2017開學訓練第二週週中總結

2017開學訓練第二週週中總結

  最近看了一下有關於線段樹的部落格:

  首先是這個題目:buy ticket

  題目大意是:一些人來排隊買票,第i個人想站在第x[i]人的後面,他的val是y[i],問最終結果是一個怎麼樣的val序列

  dalao的程式碼有些奇特,解釋也很簡單,從main函式裡面看,大概是用線段樹存他的最終位置的位置,一開始看有幾個疑問:

  首先,為什麼他要用線段樹存區間長度。

  第二,為什麼找到了這個點所在的位置之後又把區間長度更新為0。

  後來,又查閱了很多,發現線段樹中存放的是空位置的個數,這樣以上兩個疑問得以解釋,若空位置個數>=pos+1,查閱左孩子,反之查閱右孩子,最後將他放到恰當的位置。

  總結一下這個問題有點類似於線段樹處理插入問題。處理方法就是最後一個先進(因為最後一個元素一定能得到他想要的位置)然後用線段樹存放空位置的個數,以此解決。

  接下來又看到一個題目:

  誰能拿到最多的糖果。

  題目的大意是這樣的:一圈孩子,編號為k的孩子先出列,然後對於他手上的數字,若為正數,則讓左手邊第數字個人出列,反之讓右手邊第數字個人出列,並拿到出列次序的約數個數個糖果。

  這個題目看似是上面那個題目的逆運算(上面的那個題目進行的是插入的操作,下面的這個題目進行的是刪除的操作)但是這兩個題目的程式碼如出一轍,都有這樣一段:

  1.     int query(int pos,int
     r)  
  2.     {  
  3.         tree[r].cnt--;  
  4.         if(tree[r].left==tree[r].right) return tree[r].left;  
  5.         else
  6.         {  
  7.             if(pos<tree[r*2].cnt) return query(pos,r*2);  
  8.             elsereturn query(pos-tree[r*2].cnt,r*2+1);  
  9.         }  
  10.     } 

  這段程式碼在第一個題目中的意思是插入人到pos位置,第二個題目中則是將左手(右手)第pos個人刪除。

  細細思考之下,這兩個題目正是同一種操作,只不過第一個題是第二個題目的逆向思維,但是無論怎麼執行,我暫時還是想不明白為啥這個程式碼的執行結果會有那種含義,題解上的解釋少之又少,朝著我自己思維的方式思考又很難得到相應的結果,於是姑且將這段程式碼記作是刪除元素的一個模板。