zoukankan      html  css  js  c++  java
  • 树链剖分

    思想 把树拆分成 一条一条的线段 变成1条线

    首先先把树建立起来

     两次dfs

     第一次求 重儿子 son,每一个点的深度,父亲;

    void dfs1(int r,int f)  dfs1(r,0)
    {
            fa[r]=f;
            dep[r]=dep[f]+1;
            vis[r]=1;
            int maxz=0;
            sz[r]=1;     ////   包含自己了的 
            for(ri i=0;i<p[r].size();i++)
            {
                int b=p[r][i];
                if(vis[b]) continue ;
                dfs1(b,r);
                sz[r]+=sz[b];
                if(maxz<sz[b])
                {
                    son[r]=b;
                    maxz=sz[b];
            }
         }
            
    }
    View Code

    第二次求dfs 建立新的 重链 排序 (用于线段树)

    int id[M],hao[M];
    int cur,top[M],addr[M];
    void dfs2(int r,int f)
    {
        vis[r]=1;
        id[r]=++cur;        // 树节点的新id  
        addr[cur]=r;        // 新id对应的原来的树节点 后面 建立 线段树的时候要用到。 
        top[r]=f;           
        
        if(son[r]) dfs2(son[r],f);   // 重链 
        
        for(ri i=0;i<p[r].size();i++)
        {
            int b=p[r][i];
            if(vis[b]) continue;
            dfs2(b,b);    // 新开 重链 
        }
        hao[r]=cur;         // 子树 的 最后的 id 
    }
    View Code

    最后 就是求树的LCA般修改

    小注意: 在用线段树的时候 都是新id 调用函数的时候不要忘记了

    void xlca(int a,int b,int k)  /// 用到lca关于线段树的内容 都是 用 新的id 不要忘记了 
    {
        while(top[a]!=top[b])
        {
            if(dep[top[a]]>dep[top[b]])  // 记住是看top的深度 
            swap(a,b);
            xiu(id[top[b]],id[b],1,k);  // 每爬一次要更改一下 
            b=fa[top[b]];
        }
        if(dep[a]>dep[b]) swap(a,b);
        xiu(id[a],id[b],1,k); // 线段树的 用 新id  
    }
    View Code

    LAC般查询

    注意:函数一定要返回 ans,不要忘记了;

    long long clca(int a,int b) // int 型的函数 一定要return 不然返回就是0了 一定要记住 
    {
           long long ans=0;
            while(top[a]!=top[b])
            {
             if(dep[top[a]]>dep[top[b]])
             swap(a,b);
             ans=(ans+qu(id[top[b]],id[b],1))%P;
              b=fa[top[b]];
            }
        if(dep[a]>dep[b]) swap(a,b);
           ans=(ans+qu(id[a],id[b],1))%P;
           return ans;
    }
    View Code

    线段树

    4倍空间 4倍空间

    修改时的向上传递不要忘记了

    建树的时候 时 tr【i】=val【dras【L】】时和新ID 对应那个树点,不要直接 L;

    struct xdhsu{
        int l,r;
        long long val;
    }tr[M];
    void build(int l,int r,int i)      //     建立 线段树  
    {   
         tr[i].l=l;tr[i].r=r;
        if(l==r)
        {
            tr[i].val=val[addr[l]];   ////// 这个很重要  l是 新的id 要找到他 对应的 原来的 那个值 
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,i<<1);
        build(mid+1,r,i<<1|1);
        tr[i].val+=tr[i<<1].val;
        tr[i].val%=P;
        tr[i].val+=tr[i<<1|1].val;
        tr[i].val%=P;
    }
    
    int lz[M];
    
    void down(int i)  // 线段树的向下更新 , 注意懒标记是来改儿子 
    {
        if(!lz[i]) return ;
        lz[i<<1]+=lz[i];lz[i<<1]%=P;
        lz[i<<1|1]+=lz[i];lz[i<<1|1]%=P;
        tr[i<<1].val+=(tr[i<<1].r-tr[i<<1].l+1)*lz[i]%P;
        tr[i<<1|1].val+=(tr[i<<1|1].r-tr[i<<1|1].l+1)*lz[i]%P;
        lz[i]=0;
    } 
    void xiu(int l,int r,int i,int k)
    {
        if(l>tr[i].r||r<tr[i].l) return ;
        if(l<=tr[i].l&&r>=tr[i].r)
        {
            tr[i].val+=(tr[i].r-tr[i].l+1)*k%P;
            lz[i]+=k%P; //// ky ba
            return ;     /// 返回很重要 
        }
        down(i);
        xiu(l,r,i<<1,k);
        xiu(l,r,i<<1|1,k);
        tr[i].val=(tr[i<<1].val+tr[i<<1|1].val)%P; // 向上更新特别重要 
    }
    
    long long  qu(int l,int r,int i)
    {
        if(l>tr[i].r||r<tr[i].l) return 0;
        if(l<=tr[i].l&&r>=tr[i].r)
        {
            
            return tr[i].val%P;    
        }
        down(i); // 下穿 
        return (qu(l,r,i<<1)+qu(l,r,i<<1|1))%P;
    }
    View Code

      

  • 相关阅读:
    jvm 垃圾收集算法
    jvm 判断对象死亡
    jvm 内存分配
    jvm 对象奥秘
    mysql事务测试及delete和update是使用行级锁,还是表级锁
    sql语句中where后边的哪些条件会使索引失效 -- SQL语句优化
    java nio详解
    mysql数据库优化概述详解
    java 序列化和反序列化
    java io框架详解
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/11688789.html
Copyright © 2011-2022 走看看