• 【树】树链剖分学习笔记


    隔了俩月,有点看不明白这个模板Σ(っ °Д °;)っ  然后就再看了一遍.....

    需要注意的是:

    一个节点x所在重链的顶端 即 top[x],与x之间的那条链的所有节点 的dfs序是连续的

    所以如果节点x的父亲节点fa与x的dfs序 不连续,则top[x]=x

    因为 dfs序是以重链为优先确定的。

    所以根据重链可以保证线段树区间的连续性和正确性  


    洛谷P3384树链剖分

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+50;
    
    vector<int>p[maxn];
    int val[maxn],mod;
    
    
    int siz[maxn],dep[maxn],fad[maxn],son[maxn];
    int top[maxn],tid[maxn],rnk[maxn],cnt;
    /*
    siz[i] 保存以i为根的树的大小
    dep[i]  i节点的深度
    fad[i]  i的父亲
    son[i]  i的重儿子
    top[i]  重链的顶端节点
    tid[i]  i的新编号(dfs) 
    rnk[i]  rnk[tid[i]]=i
    */
    inline void dfs1(int u,int fa,int d)
    {
        /*
        u  当前节点 
        fa  父亲 
        d  深度 
        */
        dep[u]=d;
        fad[u]=fa;
        siz[u]=1;
        
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v==fa)continue;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    
    inline void dfs2(int u,int t)
    {
        /*
        u  当前节点 
        t  顶端重节点 
        */
        top[u]=t;
        tid[u]=++cnt;
        rnk[cnt]=u; 
        if(!son[u])return;//当前节点不在重链上
        dfs2(son[u],t);
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
        }
    }
    
    struct kkk{
        int l,r;ll sum,la;
    }tree[maxn<<2];
    
    inline void build(int k,int l,int r)
    {
        tree[k].l=l;tree[k].r=r;
        if(l==r)
        {
            tree[k].sum=val[rnk[l]]%mod;
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod;
    }
    inline void down(int k)
    {
        tree[k<<1].sum=(tree[k<<1].sum+(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la)%mod;
        tree[k<<1|1].sum=(tree[k<<1|1].sum+(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la)%mod;
        tree[k<<1].la=(tree[k<<1].la+tree[k].la)%mod;
        tree[k<<1|1].la=(tree[k<<1|1].la+tree[k].la)%mod;
        tree[k].la=0;
    }
    inline void add(int k,int l,int r,ll w)
    {
        if(l<=tree[k].l&&tree[k].r<=r)
        {
            tree[k].la=(tree[k].la+w)%mod;
            tree[k].sum=(tree[k].sum+(tree[k].r-tree[k].l+1)*w)%mod;
            return;
        }
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        if(l<=mid)add(k<<1,l,r,w);
        if(r>mid)add(k<<1|1,l,r,w);
        tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod;
    }
    inline int query(int k,int l,int r)
    {
        if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        ll ans=0;
        if(l<=mid)ans=(ans+query(k<<1,l,r))%mod;
        if(r>mid)ans=(ans+query(k<<1|1,l,r))%mod;
        return ans;
    }
    inline void addline(int x,int y,ll w)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            add(1,tid[top[x]],tid[x],w);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        add(1,tid[x],tid[y],w);
    }
    inline int calline(int x,int y)
    {
        ll ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans=(ans+query(1,tid[top[x]],tid[x]))%mod;
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        ans=(ans+query(1,tid[x],tid[y]))%mod;
        return ans;
    }
    
    int main()
    {
        int n,m,G,i,u,v,w,op;
        scanf("%d%d%d%d",&n,&m,&G,&mod);
        for(i=1;i<=n;i++)scanf("%d",&val[i]);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            p[u].push_back(v);
            p[v].push_back(u);
        }
    //    memset(siz,0,sizeof(siz));
        memset(son,0,sizeof(son));
        dfs1(G,0,1);
        dfs2(G,G);
        build(1,1,n);
        while(m--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d%d",&u,&v,&w);
                addline(u,v,w%mod);
            }
            else if(op==2)
            {
                scanf("%d%d",&u,&v);
                printf("%d
    ",calline(u,v)%mod);
            }
            else if(op==3)
            {
                scanf("%d%d",&u,&w);
                add(1,tid[u],tid[u]+siz[u]-1,w%mod);
            }
            else if(op==4)
            {
                scanf("%d",&u);
                printf("%d
    ",query(1,tid[u],tid[u]+siz[u]-1)%mod);
            }
        }
    }

    L. Subway Lines

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+50;
    
    vector<int>p[maxn];
    
    
    int siz[maxn],dep[maxn],fad[maxn],son[maxn];
    int top[maxn],tid[maxn],rnk[maxn],cnt;
    /*
    siz[i] 保存以i为根的树的大小
    dep[i]  i节点的深度
    fad[i]  i的父亲
    son[i]  i的重儿子
    top[i]  重链的顶端节点
    tid[i]  i的新编号(dfs) 
    rnk[i]  rnk[tid[i]]=i
    */
    inline void dfs1(int u,int fa,int d)
    {
        /*
        u  当前节点 
        fa  父亲 
        d  深度 
        */
        dep[u]=d;
        fad[u]=fa;
        siz[u]=1;
        
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v==fa)continue;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    
    inline void dfs2(int u,int t)
    {
        /*
        u  当前节点 
        t  顶端重节点 
        */
        top[u]=t;
        tid[u]=++cnt;
        rnk[cnt]=u; 
        if(!son[u])return;//当前节点不在重链上
        dfs2(son[u],t);
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
        }
    }
    
    struct kkk{
        int l,r,sum,la;
    }tree[maxn<<2];
    
    inline void build(int k,int l,int r)
    {
        tree[k].l=l;tree[k].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    inline void down(int k)
    {
        tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la;
        tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la;
        tree[k<<1].la+=tree[k].la;
        tree[k<<1|1].la+=tree[k].la;
        tree[k].la=0;
    }
    inline void add(int k,int l,int r,ll w)
    {
        if(l<=tree[k].l&&tree[k].r<=r)
        {
            tree[k].la+=w;
            tree[k].sum+=(tree[k].r-tree[k].l+1)*w;
            return;
        }
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        if(l<=mid)add(k<<1,l,r,w);
        if(r>mid)add(k<<1|1,l,r,w);
        tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    }
    inline int query(int k,int l,int r)
    {
        if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        int ans=0;
        if(l<=mid)ans+=query(k<<1,l,r);
        if(r>mid)ans+=query(k<<1|1,l,r);
        return ans;
    }
    inline void addline(int x,int y,int w)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            add(1,tid[top[x]],tid[x],w);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        add(1,tid[x],tid[y],w);
    }
    inline int calline(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans+=query(1,tid[top[x]],tid[x]);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        ans+=query(1,tid[x],tid[y]);
        return ans;
    }
    
    int main()
    {
        int n,q,i,u,v,x,y;
        scanf("%d%d",&n,&q);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            p[u].push_back(v);
            p[v].push_back(u);
        }
        memset(son,0,sizeof(son));
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        while(q--)
        {
            scanf("%d%d%d%d",&u,&v,&x,&y);
            addline(u,v,1);
            printf("%d
    ",calline(x,y));
            addline(u,v,-1);
        }
    }

    洛谷P2420

    因为不太会处理边权,所以干脆把边权设成一个点,点权为边权,连接点的点权就为0 。

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+50;
    
    
    vector<int>p[maxn];
    int val[maxn]; 
    
    
    int siz[maxn],dep[maxn],fad[maxn],son[maxn];
    int top[maxn],tid[maxn],rnk[maxn],cnt;
    /*
    siz[i] 保存以i为根的树的大小
    dep[i]  i节点的深度
    fad[i]  i的父亲
    son[i]  i的重儿子
    top[i]  重链的顶端节点
    tid[i]  i的新编号(dfs) 
    rnk[i]  rnk[tid[i]]=i
    */
    inline void dfs1(int u,int fa,int d)
    {
        /*
        u  当前节点 
        fa  父亲 
        d  深度 
        */
        dep[u]=d;
        fad[u]=fa;
        siz[u]=1;
        
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v==fa)continue;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    
    inline void dfs2(int u,int t)
    {
        /*
        u  当前节点 
        t  顶端重节点 
        */
        top[u]=t;
        tid[u]=++cnt;
        rnk[cnt]=u; 
        if(!son[u])return;//当前节点不在重链上
        dfs2(son[u],t);
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
        }
    }
    
    struct kkk{
        int l,r,sum,la;
    }tree[maxn<<2];
    
    inline void build(int k,int l,int r)
    {
        tree[k].l=l;tree[k].r=r;
        if(l==r)
        {
            tree[k].sum=val[rnk[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tree[k].sum=tree[k<<1].sum^tree[k<<1|1].sum;
    }
    inline int query(int k,int l,int r)
    {
        if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
        int mid=(tree[k].l+tree[k].r)>>1;
        int ans=0;
        if(l<=mid)ans^=query(k<<1,l,r);
        if(r>mid)ans^=query(k<<1|1,l,r);
        return ans;
    }
    inline int calline(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans^=query(1,tid[top[x]],tid[x]);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        ans^=query(1,tid[x],tid[y]);
        return ans;
    }
    
    int main()
    {
        int n,m,i,u,v,w,tot;
        scanf("%d",&n);
        tot=n;
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            p[u].push_back(++tot);
            p[tot].push_back(u);
            p[v].push_back(tot);
            p[tot].push_back(v);
            val[u]=0;val[v]=0;
            val[tot]=w;
        }
        memset(son,0,sizeof(son));
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,tot);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d",&u,&v);
            printf("%d
    ",calline(u,v));
        }
    }

    洛谷P3258

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+50;
    
    
    vector<int>p[maxn];
    
    
    int siz[maxn],dep[maxn],fad[maxn],son[maxn];
    int top[maxn],tid[maxn],rnk[maxn],cnt;
    /*
    siz[i] 保存以i为根的树的大小
    dep[i]  i节点的深度
    fad[i]  i的父亲
    son[i]  i的重儿子
    top[i]  重链的顶端节点
    tid[i]  i的新编号(dfs) 
    rnk[i]  rnk[tid[i]]=i
    */
    inline void dfs1(int u,int fa,int d)
    {
        /*
        u  当前节点 
        fa  父亲 
        d  深度 
        */
        dep[u]=d;
        fad[u]=fa;
        siz[u]=1;
        
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v==fa)continue;
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
    
    inline void dfs2(int u,int t)
    {
        /*
        u  当前节点 
        t  顶端重节点 
        */
        top[u]=t;
        tid[u]=++cnt;
        rnk[cnt]=u; 
        if(!son[u])return;//当前节点不在重链上
        dfs2(son[u],t);
        for(int i=0;i<p[u].size();i++)
        {
            int v=p[u][i];
            if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
        }
    }
    
    struct kkk{
        int l,r,sum,la;
    }tree[maxn<<2];
    
    inline void build(int k,int l,int r)
    {
        tree[k].l=l;tree[k].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    inline void down(int k)
    {
        tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la;
        tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la;
        tree[k<<1].la+=tree[k].la;
        tree[k<<1|1].la+=tree[k].la;
        tree[k].la=0;
    }
    inline void add(int k,int l,int r,ll w)
    {
        if(l<=tree[k].l&&tree[k].r<=r)
        {
            tree[k].la+=w;
            tree[k].sum+=(tree[k].r-tree[k].l+1)*w;
            return;
        }
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        if(l<=mid)add(k<<1,l,r,w);
        if(r>mid)add(k<<1|1,l,r,w);
        tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    }
    inline int query(int k,int l,int r)
    {
        if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
        if(tree[k].la)down(k);
        int mid=(tree[k].l+tree[k].r)>>1;
        int ans=0;
        if(l<=mid)ans+=query(k<<1,l,r);
        if(r>mid)ans+=query(k<<1|1,l,r);
        return ans;
    }
    inline void addline(int x,int y,int w)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            add(1,tid[top[x]],tid[x],w);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        add(1,tid[x],tid[y],w);
    }
    inline int calline(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans+=query(1,tid[top[x]],tid[x]);
            x=fad[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        ans+=query(1,tid[x],tid[y]);
        return ans;
    }
    
    int main()
    {
        int n,i,u,v,w,a[maxn],ans;
        scanf("%d",&n);
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            p[u].push_back(v);
            p[v].push_back(u);
        }
        memset(son,0,sizeof(son));
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        addline(a[1],a[2],1);
        for(i=2;i<n;i++)
        {
            addline(a[i],a[i+1],1);
            add(1,tid[a[i]],tid[a[i]],-1);
        }
        add(1,tid[a[n]],tid[a[n]],-1);
        for(i=1;i<=n;i++)printf("%d
    ",query(1,tid[i],tid[i]));
    }

  • 相关阅读:
    应用市场高速下载以及网页端调起APP页面研究与实现
    linux系统下,添加硬盘并挂载到操作系统的shell 脚本范例
    linux系统下,新加硬盘并把现有的/home目录扩容。
    Java打印裴波那契数列
    JAVA排序的方法
    Java语言输出菱形图型
    Oracle中的sql脚本语言中的循环语句介绍
    Oracle存储过程的创建实例和调用实例
    数组常用方法3---新增元素
    数组常用方法2——修改数组元素。
  • 原文地址:https://www.cnblogs.com/kkkek/p/11517481.html
Copyright © 2020-2023  润新知