日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法学习:点分治

發布時間:2025/7/14 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:点分治 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【定義】

【樹的重心】所有子樹的大小都不超過整個樹大小的一半的點

【重心的求取】依次查找每個點,當此點的最大子樹最小時肯定是重心

?

?


?

【解決問題】

處理樹上路徑信息

類似這樣:

一棵樹內n個點,求距離等于k的點對個數

一棵樹內n個點,距離等于質數的點的對數

一棵樹內n個點,是否存在距離等于k的點

.....................................

?


?

【解決思路】

?直接莽,n^3的復雜度,肯定炸

所以我們需要想一種方法,能夠顯著減少其復雜度,于是就用到了分治

選取一個節點作為將這個DAG的根,使其變成一顆樹,

想象一手拿著根,提溜著抖摟一下然后就成了一顆樹,下面有若干顆子樹

?

于是距離符合要求的情況有兩種,

第一種:兩個點都在同一顆子樹中

第二種:兩個點在不同子樹中,但是很明顯他們都經過了根節點

?

所以我們計算出各個點到根節點的距離,然后排序比較一番就能夠在nlogn的時間內求得答案,就能夠解決第二種情況的問題

?

而第一種情況,我們再向下繼續進行找根變成樹的操作,他們兩個也會在不同的子樹中

這樣子,第一種情況就會變成第二種,我們也就只需要考慮如何處理第二種和如何把第一種變成第二種

?

第一種變成第二種的關鍵在于這個根的選取,如果選的根不對很有可能選出來一個鏈,然后就O(n)處理,果斷GG

怎么分治才能使層數盡量小,使兩邊盡量均衡,達到二分的效果的情況下層數更少,能夠縮減至logn,所以我們需要取重心做,

這個根是重心,所以下面的子樹的層數會是最少的

?

?

?

#include<map> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 10010; const int MAXM = 20010; const int MAXK = 10000010; struct node {int to;int val;int nt; }edge[MAXM]; int st[MAXN], ask[110],top; int siz[MAXN], f[MAXN], root; int dis[MAXN], a[MAXN], S,cnt,n,m; int ans[MAXK]; bool vis[MAXN]; void add(int x,int y,int z) {top++; edge[top] = { y,z,st[x] }; st[x] = top; } void get_root(int x, int fa) {siz[x] = 1, f[x] = 0;for (int i = st[x]; i; i = edge[i].nt){int to = edge[i].to;if (to == fa || vis[to]) continue;get_root(to, x);f[x] = max(f[x], siz[to]);siz[x] += siz[to];}f[x] = max(f[x], S - siz[x]);if (f[x] < f[root]){root = x;} } void get_dis(int x, int fa,int d) {dis[++cnt] = a[x];for (int i = st[x]; i; i = edge[i].nt){int to = edge[i].to;if (vis[to] || to == fa) continue;a[to] = d + edge[i].val;get_dis(to, x,a[to]);} } void solve(int x,int len,int w) // {cnt = 0;a[x] = len;get_dis(x, 0, len);for(int i=1;i<=cnt;i++)for (int j = 1; j <= cnt; j++){if (i != j && dis[i]+dis[j]<MAXK)ans[dis[i] + dis[j]] += w;} } void divide(int x) {solve(x, 0, 1);vis[x] = 1;for (int i = st[x]; i; i = edge[i].nt){int to = edge[i].to;if (vis[to]) continue;solve(to, edge[i].val, -1);S = siz[x], root = 0, f[0] = n;get_root(to, x);divide(root);} } int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= n-1; i++){int x, y, z;scanf("%d%d%d", &x, &y, &z);add(x, y, z);add(y, x, z);}siz[0] = 0,f[0] = n, root = 0,S=n;get_root(1, 0);divide(root);for (int i = 1; i <= m; i++){int k;scanf("%d", &k);if (ans[k])printf("AYE\n");elseprintf("NAY\n");}return 0; } View Code

?

轉載于:https://www.cnblogs.com/rentu/p/11284495.html

總結

以上是生活随笔為你收集整理的算法学习:点分治的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。