%
給定一棵有 n
nn 個點,邊權的樹,回答 m
mm 個詢問,每次詢問樹上距離為 k
kk 的點對是否存在。
資料範圍n⩽1
04,m
⩽100,邊權
⩽10000,k
⩽107
n\leqslant 10^4,m\leqslant 100,\texttt\leqslant 10000,k\leqslant 10^7
n⩽104,
m⩽10
0,邊權⩽
1000
0,k⩽
107%
點分治模板。
考慮以 u
uu 為根的子樹,這棵子樹上的路徑有兩種,一種是經過節點 u
uu 的,另一種是不經過根節點的,考慮分治。對於大小為 1
11 的子樹,無樹上路徑,直接返回。對於節點 u
uu,合併不同的兩個子樹的路徑,組成經過節點 u
uu 的一條新路徑。
對於層數為 k
kk 的樹,時間複雜度為 θ(k
log2n
)\theta(k\log_2n)
θ(klog2
n),在平均情況下良好,但當樹為一條鏈時,程式的時間複雜度將為 θ(n
2)
\theta(n^2)
θ(n2)。
對於一棵樹 n
nn 個節點的無根樹,找到乙個點,使得把樹變成以該點為根的有根樹時,最大子樹的結點數最小,那這個點就是樹的重心。
求解重心可以用dfs求出所有子樹的大小,然後動態規劃求解,時間複雜度為 θ(n
)\theta(n)
θ(n)
。如果我們選取重心作為根,然後統計從根節點出發的所有路徑(θ(n
)\theta(n)
θ(n)
),合併從根節點出發的路徑,得到所有經過根節點的路徑,接著刪除根節點,對剩下的每個子樹分別找重心,重複以上操作,便可求出所有路徑。換句話說:每個點都是根節點,但所管理的子樹大小不同,而且重心的性質保證了最壞情況下劃分的子樹總數和 θ
(log2
n)
\theta(\log_2 n)
θ(log2n
) 同階。
在合併路徑時,先將所有路徑按長度排序先列舉詢問(θ(m
)\theta(m)
θ(m)
),令當前詢問長度為 k
kk,再列舉每條路徑(θ(n
)\theta(n)
θ(n)
),令路徑長度為 w
ww,最後在路徑中二分查詢長度為 k−w
k-wk−
w 的路徑(θ
(log2
n)
\theta(\log_2n)
θ(log2n
)),注意此時兩條路徑不能屬於同乙個子樹,因而合併路徑的時間複雜度為 θ(m
nlog2
n)
\theta(mn\log_2n)
θ(mn
log2n
)。因而程式的總時間複雜度為t(n
)=θ(
mn
log22
n)
\text(n)=\theta(mn\log_2^2 n)
t(n)=θ
(mnlog22
n) **如下
#include
#define n 10010
using
namespace std;
int n,m,num,e,x,y,z,a[
110]
,rt,size,siz[n]
,f[n]
,head[n]
;bool ans[
110]
,vis[n]
;struct edgeedges[n<<1]
;struct path
} dis[n]
;template
<
typename t>
void
maxx
(t& a,
const t &b)
void
add(
int x,
int y,
int z)
; head[x]
=e;}
void
getroot
(int x,
int fa)
maxx
(f[x]
,size-siz[x]);
if(f[x]
) rt=x;
}void
dfs(
int x,
int fa,
int wh,
int d)
;for
(int i=head[x]
;i;i=edges[i]
.pre)
}void
work
(int x)
dis[
++num]
=(path)
;sort
(dis+
1,dis+num+1)
;//o(nlogn)
for(
int i=
1;i<=m;
++i)
)-dis;
while
(l<=num&&dis[pot]
.dis+dis[l]
.dis==a[i]
&&dis[pot]
.w==dis[l]
.w) pot++;if
(dis[pot]
.dis+dis[l]
.dis==a[i]
) ans[i]=1
; l++;}
}}void
solve
(int x)
}int
main()
for(
int i=
1;i<=m;
++i)
scanf
("%d"
,a+i)
; f[rt]
=size=n;
getroot(1
,0);
solve
(rt)
;for
(int i=
1;i<=m;
++i)
puts
(ans[i]
?"aye"
:"nay");
}
luogu P3806 模板 點分治1
題目描述 給定一棵有n個點的樹 詢問樹上距離為k的點對是否存在。多次詢問 可離線 我們先隨意指定乙個虛擬根root,將這棵樹轉化成無根樹 樹上的路徑可以分為兩類,1.經過根節點u的路徑 2.完全在u子樹裡 不經過u 的 對於1,用dis表示當前結點到根節點root的路徑長度,則root的子樹中兩個節...
luogu P3806 模板 點分治1
給你一棵樹,路徑有長度,多次詢問,每次給出 k,問你是否存在路徑長度為 k 的點對。這道題我們用分治的方法。那我們假設要解決乙個樹,那我們先選重心作為根節點 為了減少高度節省時間 然後就分成兩種討論,一種是路徑都在同乙個子樹中,那這個我們就可以把問題轉換為解決這個子樹。另一種就是在兩個不同的子樹中 ...
luogu P3806 模板 點分治1
給你一棵樹,路徑有長度,多次詢問,每次給出 k,問你是否存在路徑長度為 k 的點對。這道題我們用分治的方法。那我們假設要解決乙個樹,那我們先選重心作為根節點 為了減少高度節省時間 然後就分成兩種討論,一種是路徑都在同乙個子樹中,那這個我們就可以把問題轉換為解決這個子樹。另一種就是在兩個不同的子樹中 ...