之前diaoye的一道題是要用點分治寫..但是我省選前臨時學的點分治,當時又只打了幾個板子,中間又沒有寫過有關的題,於是現在就似乎不太會了,剛好昨天又講了,今天就複習一下
引用講課pp
t ppt
裡的一段話
點分治,是處理樹上路徑/連通塊的一種常見演算法。然後點分治我覺得可能也是跟容斥有關的,因為它主要思想還是先計算不考慮限制的答案再減去包含限制的答案,然後比較重要的地方就是每次都以樹的重心為根來進行分治處理。這一類問題有時可以通過lca來處理,但是有的時候複雜度會略高。
點分治,每次對當前的樹求出重心,處理所有經過重心的路徑/連通塊,然後遞迴每個子樹。
這樣,每個節點只會出現在log次分治中。
update:看來自己還是對這個演算法理解不夠… 感謝yl
soij
ulao
y ls
oiju
la
o的講解
就是有一些細節地方還是需要注意 第乙個就是每次分治對於每棵子樹又要重新確定重心,這我原來是沒有做的…重新確定重心後那麼子樹的si
zes iz
e又會改變, 所以每次處理一棵子樹的時候又要重新記一次si
zes iz
e直接上例題吧
luogu4178 tree
裸題,直接上板子即可
#include#define for(i, a, b) for(register int i = a; i <= b; ++ i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
using namespace std;
const
int maxn = 40000 + 10;
intto[maxn << 1], head[maxn], nxt[maxn << 1], v[maxn << 1], e;
int all, n, root, size[maxn], sizemax[maxn], ans;
intnow[maxn], dep[maxn], k, vis[maxn];
void add(int x, int y, int z)
void get_dep(int x, int fa)
}int cal(int x, int from)
void get_root(int x, int fa)
if(all - size[x] > sizemax[x])
sizemax[x] = all - size[x];
if(sizemax[root] > sizemax[x])
root = x;
}void solve(int x)
}int main()
all = n, sizemax[0] = int_max;
get_root(1, 0), scanf("%d", &k);
solve(root); printf("%d\n", ans);
return 0;
}
複習 動態點分治
點分治,動態點分治,等等等各種分治。因為我的智商經常欠費,導致我對於分治這個方面一竅不通。但是動態點分治這個東西我又不是沒有學過,只是過了這麼久我什麼都不會了。所以還是重新理解一下吧。首先,動態點分治需要構建出點分樹,這個很好處理。找重心是o n o n 每次重心分出來的每一棵子樹的大小都不超過o ...
筆記 點分治
基本思路 點分治,是一種針對可帶權樹上簡單路徑統計問題的演算法。對於乙個節點,只解決經過這棵子樹的根節點的路徑,對於子節點問題下推子樹。當初的主要問題是vis在幹什麼qwq,終於知道了 include include include define r register int using names...
學習筆記 點分治
點分治,其實應該叫 樹上點分治 主要用於解決 樹上路徑問題 我亂起的名字 比如,樹上是否存在長為 k 的路徑,樹上長小於 k 的路徑有多少條等等.點分治可以概括為 分治 重心 桶 就目前我做過的幾道題來說都是這個套路 我們就直接針對一道題來吧.詢問樹上距離為 k 的點對是否存在 換句話說,就是樹上是...