1. 程式人生 > >點分治經典_動態點分治

點分治經典_動態點分治

HYSBZ_3730_震波

背景:這是接觸的動態點分治第一題,開始不是很理解,看了很久,寫了很久才理解了動態的動態所在。
前置知識:靜態點分治(主要是容斥思想,一般看出來是點分治的話,想到怎麼容斥剩下的操作就很機械了,還有一種LCT,目前是我的盲區),線段樹(樹狀陣列)。可以通過寫一寫線段樹和樹狀陣列的題來理解這兩個維護的有力工具。
題目描述:給出一棵樹,第一種操作:在x點(編號,非權值)發生y長度地震,距離x不超過y的點全部被摧毀,求被摧毀的權值總和;第二種操作:將x的權值改為y。其中摧毀獨立,修改不獨立。
動態點分治模板題,一開始當靜態的做,已經自閉了,怎麼都想不出來點分治還能修改,要不是做專題,還以為是樹鏈剖分,可是好像又不對,苦想無果,開啟百度。。

淺談點分治:
其一:點分治本質還是分治,分治就是不斷將大區間劃分成小區間,小到可以簡單解決再向上合併。而動態點分治和靜態最大的區別就是他是動態的廢話,那麼要在動態中高效求解,就想到了資料結構。可是資料結構要維護,要有資料,點分治的資料(僅本題)是點權,顯然維護點權即可,但是怎麼維護較為合理?這時候就要牽扯到一點靜態點分治的思想了,我們考慮任意點u:①如果是初始重心(無向樹中,最大子樹規模最小的點),顯然只會被分治0次,然後更新多次。②如果是葉子,顯然會被分治多次,更新一次。③中間節點:分治次數與更新次數基於前兩者中間。這裡說的分治次數,指的是該點會出現在其祖先後代中的次數(顯然初始重心沒有確切存在的祖先,只有虛根0,故其不會出現在任何>0

的編號的分治之下),更新次數指的是若該點的後代被修改,他也會被更新。(因為本題求的是和值,單點更新之後,自然向上合併的時候和值會被更新)。
其二:個人覺得最關鍵的一點,就是一旦一棵樹你輸入完了,點分治的順序其實已經是確定的了,這也就是能用資料結構維護的原因。意思就是說每個點被分治的次數是可以求出來的,某一個點分治時的各種關係是確定的,自然向上合併的時候也是確定的。於是乎我們可以為每個點開兩個樹狀陣列(本題需要兩個)。

題解:對於每個點,在getrt之後,確定下來關係(getship),這裡的關係指的是:①他被分治的次數(ct[i]=j, 表示i這個點一共被分治j次)。②他在每次被分治時,距離當前重心的距離以及當前重心(dis[i][j]=k

,i點在第j次被分治時距離該次重心的距離為kfa[i][j]=ki點在第j次分治的重心是k)。③每個點維護兩個樹狀陣列,第一個表示其後代到他(不包括他自身)的答案(距離為下標,權值為資料,不用擔心距離相同,因為本題求和值,直接相加即可),第二個表示其後代到該點父親的答案(……與之前相同)。為何需要第二個陣列?假定在x處發生y地震,我們用第一個算出後代的,但是祖先的結點也可能滿足距離小於等於y,故可以暴力向上呼叫上面結點的第一個樹狀陣列求出答案。顯然,答案是會重複的,如何扣除?(靜態點分治的容斥思想),假設當前在該結點第一個樹狀陣列中統計距離k的答案,再向上用祖先的第一個樹狀陣列中統計k-dis[u][i],最後在該結點自己的第二個樹狀陣列中統計k-dis[u][i]的答案,這樣就可以去除冗餘,畫圖即可證明。對於更新,比較暴力,記住每個點兩個樹狀陣列的意義,從下往上暴力更新即可。

參考部落格: