黑科技——樹剖兩次\(dfs\)轉一次\(dfs\)!算法
重所周知,樹鏈剖分一般是要\(dfs\)兩次的,就像這樣:優化
int Fa[N],dep[N],Sz[N],son[N]; void dfs1(int x,int pre){ Fa[x]=pre,dep[x]=dep[pre]+1; Sz[x]=1; erep(i,G,x){ int y=G.to[i]; if(y==pre)continue; dfs(y,x); Sz[x]+=Sz[y]; (Sz[y]>Sz[son[x]])&&(son[x]=y); } } int L[N],R[N],Id,top[N]; void dfs2(int x,int tp){ top[x]=tp; if(son[x])dfs2(son[x],tp); erep(i,G,x){ int y=G.to[i]; if(y==Fa[x]||y==son[x])continue; dfs2(y,y); } }
可是在一些\(n\)比較大而且的卡常毒瘤題中,咱們若是使用了兩次\(dfs\)就有可能會出現\(tle\)的狀況。spa
在這時,若咱們沒法優化本質算法的狀況下咱們須要卡常。code
怎麼卡呢?利用\(dfs\)序:遞歸
代碼以下:class
int Fa[N],dep[N],Sz[N],son[N],L[N],R[N],Id[N],cnt,top[N]; void dfs1(int x,int pre){ Fa[x]=pre,dep[x]=dep[pre]+1; Sz[x]=1,L[x]=++cnt,Id[cnt]=x; erep(i,G,x){ int y=G.to[i]; if(y==pre)continue; dfs(y,x); Sz[x]+=Sz[y]; (Sz[y]>Sz[son[x]])&&(son[x]=y); } R[x]=cnt; } rep(i,1,n)top[Id[i]]=Id[i]==son[Fa[Id[i]]]?top[Fa[Id[i]]]:Id[i];
就這樣咱們只用了一次\(dfs\)就完成了樹剖的預處理操做。top
別小看這一個遞歸,他在\(n\)較大的狀況下,能夠快大概\(1\)倍。co