熟练剖分1.01

然而并不熟练剖分(雾);

他可以做什么?(大雾)

熟练想必是在熟上的练(雾雾雾) 

#define 树链 熟练

树链剖分即把树剖成很多条链,有的长有的短;

主流剖法:

  1.随机:O(1 ~ 脸 ~n)均摊后 log ;

  2.轻重链:O为 log 级 也即这里的熟练剖分;

非主流剖法:

  机房某大佬自创的按链长剖分,看起来还不错,中了迭代加深的毒吧;

下面就是蒟蒻我的不熟练剖分了;


 1.st 分链

以两遍dfs解决;

dfs1 找出每个节点重儿子 , 顺带上 fa,deep等数组;

dfs2 确定每条重链的顶点 ,链接各个重儿子 , 顺带上 nid 等数组;

void dfs1(int fu,int cur,int depth)
{
    dep[cur]=depth;//深度
    fa[cur]=fu;
//记录父亲,递归中用于无向图判断搜索方向,以及后来的转换重链 
    sub[cur]++;//子树大小,自己为根,叶结点为1;
    int pang =-1 //预备记录胖儿子 
    for(int i=Head[cur];i;i=bian[i].NE)
    {
        int _v=bian[i].TO;
        if(_v==fu)continue; 
        dfs(cur,_v,depth+1);
        sub[cur]+=sub[_v];
        if(sub[cur]>pang)
        {
            pang=sub[cur];
            zhong[cur]=_v;//记录胖儿子的数组 
        }
    } 
}
void dfs2(int cur,int tp)//tp即重链顶端 
{
    din[cur]=tp;
    dfn[cur]=++dfsxu;//记录dfs序
    //同一链上的节点必定dfs序相连    
    nid[dfsxu]=quan[cur];//以dfs序为下标存点权,方便调用 
//这个数组,nid,卡懵了我很久,望周知; 
    dfs(zhong[cur],tp);//胖儿子优先 且在相同链上 tp相同; 
    for(int i=Head[cur];i;i=bian[i].NE) 
    {
        int _v=bian[i].TO;
        if(_v==zhong[cur]||_v==fa[cur])continue;
        dfs(_v,_v);//轻儿子以自己为顶点,有自己的一条重链 
    }
} 

2.nd 构造

以dfs序够造线段树(每条链都有)

每个结点相当于以前处理数组时的原数组;

(支持区间操作的结构(splay,zkw,树状数组,lct,。。。)都行,我就不暴露自己的真实实力了(逃))


3. 区间操作

在同一链上的话,口糊就好,因为我们已经把同一条链上的信息收集过了,直接调用;

不在呢?谁知道...

蒟蒻我偷听几位大佬讨论后,发现其实是一个找LCA向上跳点的简化过程;

大致如下:

  1  :if  tp【i】!= tp【j】   == 》2      ;   else    ==》  4;

  2  :if(dep【i】> dep【j】)swap(i,j);|| 

  

猜你喜欢

转载自www.cnblogs.com/hjk-biu/p/9388386.html
今日推荐