黑科技——树剖两次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\)的情况。

在这时,若我们无法优化本质算法的情况下我们需要卡常。

怎么卡呢?利用\(dfs\)序:

代码如下:

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\)就完成了树剖的预处理操作。

别小看这一个递归,他在\(n\)较大的情况下,可以快大概\(1\)倍。

posted @ 2019-11-09 15:07  dsjkafdsaf  阅读(144)  评论(0编辑  收藏  举报