動態點分治學習筆記
唔突然不想寫那麼長的總結了
大概思想就是維護一個點分樹,這樣保證了樹高是\(\log\) 級別的,然後對於一些修改或者詢問,就可以支援諸如在點分樹上暴跳\(\text{father}\) 這樣的暴力做法了。
但是這並不是原來的樹,所以在點分樹上維護的資訊要以原樹為準。
具體題目具體分析,但大方向是在點\(i\) 維護點分樹上點\(i\) 的子樹的資訊,並且維護點\(i\) 的子樹到點分樹上\(i\) 的父親的資訊。不這樣做的話大概會把在原樹上點\(i\) 和點\(i\) 的父親(點分樹上)之間的聯通塊的答案多統計,這樣維護一下就可以減掉了。
下面是兩道題:
[BZOJ3730] 震波
Description
給定一棵樹,點有點權。要求支援修改點權,詢問距離點\(x\) 小於等於\(y\) 的點的點權和。\(n,m\leq 10^5\) 。
Sol
這是最經典的維護上面說的兩個資訊,然後減一下保證答案不重複。
就是在每個點維護兩棵以距離為下標的線段樹,分別是點分樹上點\(i\) 的子樹對於\(i\) 的點權和,以及點\(i\) 的子樹對於\(fa[i]\) 的點權和。這樣做有什麼好處?
考慮詢問\(dis=3\) ,我們先在點\(x\) 求出所有到點\(x\) 距離小於等於\(3\) 的點權和,假設\(dis(x,fa[x])=2\) ,那麼還要求出點\(x\) 的子樹中到\(fa[x]\) 距離小於等於\(1\) 的點權和,然後把這部分答案減去。原因是會在跳到\(fa[x]\) 時統計所有到\(fa[x]\) 的距離小於等於\(3-2=1\) 的點權和,這裡會重複統計,所以要提前減去。
[WC2014] 紫荊花之戀
Description
給定一棵空樹,每次會向這顆樹中新增一個節點,點帶權。每次新增完後回答樹中有多少節點對滿足兩點之間的距離小於等於兩點點權和。\(n\leq 10^5\) 。強制線上。
Sol
先假設是一棵靜態的樹,怎麼求答案?
點分治。
對於所有\(dis(i,u)+dis(j,u)\leq r[i]+r[j],(i,j)\) 是一對合法點對。移項發現兩項獨立,於是可以在節點\(u\) 維護一棵平衡樹來統計\(\text{rank}\) 。
那動起來怎麼辦呢?
動態點分治+定期重構點分樹。
每次還是加一個節點,然後在點分樹上暴跳\(\text{father}\) 來統計答案。
但是如果是一條鏈怎麼辦?
所以需要像替罪羊樹那樣定期重構。
然後重構時有一些實現方面的問題,比如說每個點要開兩個\(\text{vector}\) 記錄每個點在點分樹上的祖先和在原樹上到祖先的距離,還要開個\(\text{vector}\) 記錄這個點在點分樹上的所有兒子。這樣做完全是為了方便重構點分樹。
具體重構就是,找到最靠上且需要重構的點,然後把它的子樹全部掃一遍,求出重心,然後遞迴去做。說起來挺簡單但是有一點細節?記得在平衡樹\(\text{pushup}\) 的時候\(+1\) ,把自己也放進存兒子的\(\text{vector}\) 裡。就沒啥了。