關於分治的入門專題

2021-08-03 06:31:06 字數 1668 閱讀 8859

最近一直刷bzoj,沒有開新專題,所以開了個新專題分治。

主要是刷到幾道題要用分治,但不會,所以本蒟蒻決定入個門。

首先先看個qzc大神的**:《

分治演算法

在樹的路徑問題中的應用

》然後來到入門題:poj1741,題目大意詳見**。

orz   lishaozhe1024

我們隨便找一點作為根,將無根樹轉化為有根樹

那麼樹的路徑分為兩種 , 一種是經過樹根的 , 另外一種是不經過樹根

如果我們有辦法求出路徑經過樹根的有多少對點 ,那麼不經過樹根的,只要遞迴子樹就行了 , 這樣問題就得到解決了

那麼分治 , 我們先看如何分 ,在最壞的情況下,比如一條鏈的情況,我們可能要遞迴 n 次 , 這樣的複雜度肯定不是我們想要的 。

那麼如果避免這樣的情況 , 就是在選擇根的時候,我們選擇這棵樹的「重心」,所謂樹的重心,就是這個點的所有子樹的結點個數的最大值是最小的。

如何求樹的重心 , 先dfs一遍,求出每個結點的子樹的結點的最大值dp[i]和以這個結點為根的樹的結點總和sum[i]。那麼第二次dfs的時候,比較dp[i] 和 sum[root] - sum[i] 的最大值即可。

這樣的分治策略 ,最壞情況的遞迴次數是 logn 的

然後看如何治 ,我們要求的是有多少點對的路徑之和小於等於k,並且是經過根節點的。

那麼我們先一遍dfs求出每個結點到根節點的距離 , 放在乙個陣列中 , 排完序之後 , 我們可以 two pointer 求出選兩個數,和小於等於k的方案數( 複雜度為o(n) ) 。

這樣求得的***括了兩個頂點都來自同一子樹的情況 , 這樣就不經過根節點了, 所以我們要把這些情況減掉

我們只要對各個子樹同樣求一遍答案,減去即可。

假如排序我們用快排,那麼整個演算法的複雜度是 o( nlognlogn )

**:#include#include#include#includeusing namespace std;

const int n=10010;

const int m=50100;

int n,k;

struct nodesa[m];int len,first[n];

bool vis[n];

int ans,mi,mx[n],size[n],root,num;

void init()

void ins(int x,int y,int z)

void dfssize(int x,int fa) }}

void dfsroot(int r,int u,int fa)

edge[maxn<<1];

struct n

t[maxn];

bool cmp(n x, n y)

}void dfssize(int u, int fa)

}void getnum(int u, int fa)

}void getg(int u, int fa, int dep, int val)

}void dfs(int u)

int tot=0;

for(i=head[u];i!=-1;i=edge[i].next)

sort(t,t+tot,cmp);

int lim=k-color[u];

for(i=0;i<=t[tot-1].num;i++) f[i]=-inf;

for(i=0;i

分治入門 樹分治

分治思想 劃分子問題,解決子問題,合併子問題 題目 poj1741 題意 給定一棵含有n個節點的無向帶權樹,滿足距離 k的兩點共有多少對?n 1e4 題解 1 首先找到樹a的重心,重心指的是乙個節點,將該節點刪去之後剩下的最大子樹的節點數最小 將其作為樹a的根。在數列的分治之中我們是直接去區間的中間...

分治入門 平面分治

分治思想 劃分子問題,解決子問題,合併子問題 題目 uva 10245 題意 在乙個二維平面內給定n個點,求最近的兩個點的距離。n 10000 題解 直接暴力列舉所有點是肯定行不通的。那麼基於分治的思想 按照橫座標排序後,分成兩個部分,那麼最近距離的點對就是以下的情況 1 兩個點均屬於乙個區域 2 ...

入門專題 VUEJS

vuejs是乙個前端js框架 mvvm,資料驅動 可開發單頁面應用程式 spa 傳統多頁面開發也可以引用 src assets logo.png router view v model testinput v text inputfilter testinput h1 div template ex...