嗯,蒟蒻我剛學的就記錄一下
以洛谷的tree為模板講解:洛谷題目傳送門
了解點分治之前,首先要知道什麼是重心(要用到)
簡單來說,就是子樹最小的那個節點,我們需要o(n)地找到他來保證複雜度
void get_root(rg int now,rg int fm)
num=max(num,tot-size[now]);//tot是總點數
//tot-size[now]是父親那邊(不是兒子)的「子樹」大小
if(max>num)max=num,root=now;//是否更新
}
個人認為這裡還是比較簡單的,自己畫個圖簡單明瞭了
找到重心後把重心刪掉,變成兩個連通塊,再分別找重心,把重心與之前找的重心相連邊,不斷遞迴建成一棵新樹,就是點分樹
&&優點:嚴格log層(不信自己驗證)
這道題暫時不要用,但是是點分治的乙個重要知識點……
首先了解幾個特點(暫時不用理解,等下自然就懂)
嗯,不想寫了,所以安利一波機房大佬的部落格理解吧,一時半會真的講不清,至少我問了很久才懂(主要是不想畫圖來講解了,畫圖就很容易理解了)ycb blog
我也推薦幾道題吧,畢竟沒總結良心過不去(其實就是給自己日後複習用的)
#include#include#include#include#include#include#include#include#include#include#include#define rg register
#define il inline
#define lst long long
#define ldb long double
#define n 40050
using namespace std;
const int inf=1e9;
int n,k,cnt,tot,ans;
int max,root,le,ri;
struct edgeljl[n<<1];
int hd[n];
int size[n],vis[n];
int q[n],dis[n];
il int read()
while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
}il void add(rg int p,rg int q,rg int o)
;hd[p]=cnt;
}void get_root(rg int now,rg int fm)
num=max(num,tot-size[now]);
if(max>num)max=num,root=now;
}void get_dis(rg int now,rg int fm)
}il int query(rg int now,rg int base)
return res;
}void divide(rg int now,rg int fm)
}int main()
{ n=read();
for(rg int i=1;itree(就在上面)
[國家集訓隊]聰聰可可(題解)
【模板】點分治1(題解)
點分治學習
嗯,蒟蒻我剛學的就記錄一下 以洛谷的tree為模板講解 洛谷題目傳送門 了解點分治之前,首先要知道什麼是重心 要用到 簡單來說,就是子樹最小的那個節點,我們需要o n 地找到他來保證複雜度 void get root rg int now,rg int fm num max num,tot size...
點分治學習
例題 考慮一顆邊權為1的樹上有多少個路徑正好為k的點對。我們考慮乙個這樣的樹,現在問,這個樹上有多少個點對之間的距離為k。首先,我們從根結點開始考慮。那麼我們可以把所有的路徑劃分為兩個部分 1,經過根結點的路徑。2,不經過根結點的路徑。對於第一種路徑,經過根節點,那麼就是x root y。也就是說這...
點分治學習筆記
點分治主要用來處理樹上路徑問題,可以統計樹上點到點的所有路徑,複雜度o nlogn 基於樹上的結點進行分治,不斷將一棵樹拆成多顆子樹處理 選擇點時為了防止退化成鏈的情況,如果選點後左右子樹越大,遞迴層數越多,時間越慢,反之則越快,我們每次選擇子樹內的重心 void getroot int u,int...