點分治就是在一棵樹中,將每個點分治……
基本概念:
點分治:將一棵無根樹變成有根樹,再分別處理每棵有根子樹。
重心:在一棵樹中,這個點的最大子樹是所有點中最小的。也可以說是刪除該點時,樹內剩下的子樹最大節點數最小。
size[i]表示以i為根的子樹節點數量。
如何求重心??求出size,什麼是定義,就怎麼求。一般來說總(不是每次)時間複雜度為o(n)
找重心的**(這裡的**都對應著下面的例題):
void findroot(int x,int fa)
mx[x]=max(mx[x],nn-size[x]);
if (mx[x]int main()
**中的nn即為這個子樹的節點數。
為什麼要找重心??
為了使時間複雜度少,每棵子樹都要盡量小,那麼根一定是重心。
給出一棵帶邊權的樹,問有多少對點的距離<=len
1、對於每個點,找出有多少對經過這個點的點對距離在len內,總(不是每次)o(n),減去在子節點中算重的。
2、刪掉這個點,對於剩下的一堆子樹中再重複做。
為了保證時間複雜度,每次都要找重心。
**:
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define n 11000
#define clear(a) memset(a,0,sizeof(a));
using namespace std;
int n,nn,len,m,size[n],mx[n],last[n*10],next[n*10],to[n*10],tot,root,ans;
ll data[n*10];
bool bz[n];
ll deep[n],dep[n];
void putin(int
x,int
y,int z)
void findroot(int
x,int fa)
mx[x]=max(mx[x],nn-size[x]);
if (mx[x]x;
}void getdeep(int
x,int fa)
deep[++tot]=dep[x];
}int calc(int
x) else j--;
}return ans;
}void dg(int
x,int fa)
}int main()
mx[0]=2147483647;nn=n;root=0;findroot(1,0);
dg(root,0);
printf("%d",ans);
}
樹中點對距離(點分治)
給出一棵帶邊權的樹,問有多少對點的距離 len 這是一道點分治的經典題目,可以給點分治的初學者練手。點分治,顧名思義就是把每個點分開了處理答案。假設,目前做到了以x為根的子樹。先求出子樹中每個點到根的距離di s 對於兩個點 i 和 j,如果di si d isj k 那麼 i j 就是乙個合法的點...
點分治入門 樹中點對距離詳(?)解
其中樹最多有10000個點,len maxlongint 這是一道模板題目。對於乙個點x,我們考慮如何求解經過x點的路徑方案數,設為f x 考慮直接從x出發做一遍dfs,算出所有未到過的點到x點的距離,然後排序。設兩個指標,如果length l length r len,那麼length l len...
點分治模板 (例題 樹中點對距離) 待更新 坑
description 給出一棵帶邊權的樹,問有多少對點的距離 len c表示最大兒子的節點的size size表示子樹大小 處理子樹大小 void get size int x,int y 找重心 size r size x 是x上面部分的樹的尺寸,跟x的最大孩子比,找到最大孩子的最小差值節點 v...