最近一直刷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...