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

      

  • 相关阅读:
    洛谷 1339 最短路
    洛谷 1330 封锁阳光大学 图论 二分图染色
    洛谷 1262 间谍网络 Tarjan 图论
    洛谷 1373 dp 小a和uim之大逃离 良心题解
    洛谷 1972 莫队
    洛谷 2158 数论 打表 欧拉函数
    洛谷 1414 数论 分解因数 水题
    蒟蒻的省选复习(不如说是noip普及组复习)————连载中
    关于筛法
    关于整数划分的几类问题
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/11688789.html
Copyright © 2011-2022 走看看