給定一棵數,問樹中長度<=k的簡單路徑有多少條。
如果純dfs的話,時間複雜度是o(n
3)
o(n^3)
o(n3
),必然超時。
於是我們考慮用點分治來做。
主要演算法流程有以下幾步:
求樹的重心(乙個點,其所有的子樹中最大的子樹節點數最少)p;
從p出發進行dfs,將子樹節點存起來並按照權值排序;
進行calc§操作,由於排序後的節點滿足單調性,可以通過二分來求出結果
之前的結果包含了一些共用路徑的,所以遞迴子樹進行操作,減去占用公共邊的結果
#include
#include
#include
#include
#include
using
namespace std;
const
int maxn =
100005
;void
read
(int
&x)while
(s>=
'0'&&s<=
'9')
x *= f;
}int n,k,root,minbalance,ans,tsize,m;
vectorint,
int>
>e[maxn]
;int siz[maxn]
,a[maxn]
;bool vis[maxn]
;vector<
int> dep;
void
getroot
(int x,
int fa)
} maxsubtree =
max(maxsubtree,tsize-siz[x]);
if(maxsubtree}void
dfs(
int x,
int fa)}}
intcalc
(int x,
int w)
return res;
}void
exec
(int x)}}
intmain()
);e[y]
.push_back()
;}tsize = minbalance = n;
getroot(1
,0);
exec
(root)
; cout << ans << endl;
}return0;
}
點分治初探
點分治,適用於樹上的路徑統計問題,本質上是用分治思想優化的暴力。其實學會思想就很簡單了。給定一棵樹和乙個整數 k 求樹上長度為 k 的路徑總數。顯然共有 n n 1 條路徑,暴力統計複雜度過高。考慮路徑情況,發現我們可以將其分為兩類 經過根節點的路徑。不經過根節點的路徑。運用分治思想可以發現,我們可...
點分治 動態點分治
實在拖得太久了。先扔掉資料 分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n 變成nlogn。兩個問題,如何區分和如何算答案。對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去...
點分治與動態點分治
點分治一般是用於解決樹上路徑問題。樹的重心 把重心這個點割掉後,使所形成的最大的聯通塊大小最小的點。可以證明重心子樹的大小最大不會超過 n over 2 重心可以通過 dfs 一遍求出。maxsiz x 表示割掉點x後所形成的的最大的聯通塊的大小 void dfs int x,int fa max ...