黑科技——樹剖兩次dfs轉一次dfs!

黑科技——樹剖兩次\(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

相關文章
相關標籤/搜索