例題:考慮一顆邊權為1的樹上有多少個路徑正好為k的點對。
我們考慮乙個這樣的樹,現在問,這個樹上有多少個點對之間的距離為k。
首先,我們從根結點開始考慮。
那麼我們可以把所有的路徑劃分為兩個部分
1,經過根結點的路徑。2,不經過根結點的路徑。
對於第一種路徑,經過根節點,那麼就是x->root->y。
也就是說這條路徑是root的兩個不同子樹的鏈組成。
那麼不就是考慮d[x] + d[y] == k的點對嗎。
我們可以求的root到每個結點的距離,存放到d陣列裡面。
同時,儲存每個結點是root的哪個子樹下面的點 用b陣列儲存,儲存root能到那些結點,用point陣列儲存。
那麼我們可以把point陣列根據距離進行排序。
從而用兩個指標的方式將其進行統計。
對於第二種路徑來說,
不就是遞迴第一種路徑嘛。
#include"stdio.h"#include"string.h"
#include"algorithm"
using namespace std;
inline int read()
while(c>='0'&&c<='9')
return x*f;
}const int n = 100010;
int head[n],ver[n],next[n],edge[n],tot;
int n,m;
int v[n],size[n],ans,root;///找到樹的重心
int vis[n];
int d[n],b[n],point[n],top;
int cnt[n];
int num,k;
void add(int x,int y,int w)
void get_root(int x,int far,int n)
max_part = max(max_part,n - size[x]);
if(max_part < ans || root == 0)
return ;
}void get_dist(int x,int far,int ww,int from)
}int cmp(int x,int y)
void calc(int root)
sort(point + 1,point + top + 1,cmp);
int left = 1,right = top;
while(left < right)
else break;
r --;
}num += xx;
left ++;}}
}void solve(int u)
}int main()
ans = n;
get_root(1,0,n);
solve(root);
printf("%d\n",num);
}
點分治學習
嗯,蒟蒻我剛學的就記錄一下 以洛谷的tree為模板講解 洛谷題目傳送門 了解點分治之前,首先要知道什麼是重心 要用到 簡單來說,就是子樹最小的那個節點,我們需要o n 地找到他來保證複雜度 void get root rg int now,rg int fm num max num,tot size...
點分治學習
嗯,蒟蒻我剛學的就記錄一下 以洛谷的tree為模板講解 洛谷題目傳送門 了解點分治之前,首先要知道什麼是重心 要用到 簡單來說,就是子樹最小的那個節點,我們需要o n 地找到他來保證複雜度 void get root rg int now,rg int fm num max num,tot size...
點分治學習筆記
點分治主要用來處理樹上路徑問題,可以統計樹上點到點的所有路徑,複雜度o nlogn 基於樹上的結點進行分治,不斷將一棵樹拆成多顆子樹處理 選擇點時為了防止退化成鏈的情況,如果選點後左右子樹越大,遞迴層數越多,時間越慢,反之則越快,我們每次選擇子樹內的重心 void getroot int u,int...