2017開學訓練第二週週中總結
最近看了一下有關於線段樹的部落格:
首先是這個題目:buy ticket
題目大意是:一些人來排隊買票,第i個人想站在第x[i]人的後面,他的val是y[i],問最終結果是一個怎麼樣的val序列
dalao的程式碼有些奇特,解釋也很簡單,從main函式裡面看,大概是用線段樹存他的最終位置的位置,一開始看有幾個疑問:
首先,為什麼他要用線段樹存區間長度。
第二,為什麼找到了這個點所在的位置之後又把區間長度更新為0。
後來,又查閱了很多,發現線段樹中存放的是空位置的個數,這樣以上兩個疑問得以解釋,若空位置個數>=pos+1,查閱左孩子,反之查閱右孩子,最後將他放到恰當的位置。
總結一下這個問題有點類似於線段樹處理插入問題。處理方法就是最後一個先進(因為最後一個元素一定能得到他想要的位置)然後用線段樹存放空位置的個數,以此解決。
接下來又看到一個題目:
誰能拿到最多的糖果。
題目的大意是這樣的:一圈孩子,編號為k的孩子先出列,然後對於他手上的數字,若為正數,則讓左手邊第數字個人出列,反之讓右手邊第數字個人出列,並拿到出列次序的約數個數個糖果。
這個題目看似是上面那個題目的逆運算(上面的那個題目進行的是插入的操作,下面的這個題目進行的是刪除的操作)但是這兩個題目的程式碼如出一轍,都有這樣一段:
-
int query(int pos,int
- {
- tree[r].cnt--;
- if(tree[r].left==tree[r].right) return tree[r].left;
- else
- {
- if(pos<tree[r*2].cnt) return query(pos,r*2);
- elsereturn query(pos-tree[r*2].cnt,r*2+1);
- }
- }
這段程式碼在第一個題目中的意思是插入人到pos位置,第二個題目中則是將左手(右手)第pos個人刪除。
細細思考之下,這兩個題目正是同一種操作,只不過第一個題是第二個題目的逆向思維,但是無論怎麼執行,我暫時還是想不明白為啥這個程式碼的執行結果會有那種含義,題解上的解釋少之又少,朝著我自己思維的方式思考又很難得到相應的結果,於是姑且將這段程式碼記作是刪除元素的一個模板。