zoukankan      html  css  js  c++  java
  • 【模板】树链剖分

    惨了惨了我好喜欢这个算法呜呜呜快超过(MST)

    树剖涉及的知识:(LCA)(最近公共祖先/倍增),线段树

    
    已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
    
    操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
    
    操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
    
    操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
    
    操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
    
    

    (我理解中的)树剖就是将树上的问题,转化为线性来处理。

    通过两次搜索,对每个结点加以一些标记,其中还包括对结点进行新的编号

    编号之后就满足一个结点为根的子树,它们的新编号是连续的。

    于是就可以维护区间和了w!(线段树好啊233)

    (懒得写太多了)

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    #define MAXN 233333
    //变量们!
    int n,m,r,mod;
    
    int tot=0,cnt=0;
    
    int ans[MAXN<<2],tag[MAXN<<2];
    
    struct qwq
    {
        int nex,to;
    }e[MAXN];
    int h[MAXN];
    
    int w1[MAXN],w2[MAXN];
    
    int dep[MAXN],top[MAXN],siz[MAXN],fa[MAXN],id[MAXN],son[MAXN];
    //end. 
    
    void add(int x,int y)
    {
        e[++tot].to=y;
        e[tot].nex=h[x];
        h[x]=tot;
    }
    
    
    //seg_tree
    #define leftson cur<<1
    #define rightson cur<<1|1
    #define mid ((l+r)>>1)
    #define push_up ans[cur]=ans[leftson]+ans[rightson]; ans[cur]%=mod
    #define push_down lazyadd(leftson,l,mid,tag[cur]); lazyadd(rightson,mid+1,r,tag[cur]); tag[cur]=0
    inline void lazyadd(int cur,int l,int r,int del)
    {
        tag[cur]+=del;
        ans[cur]+=del*(r-l+1);
        ans[cur]%=mod;
    }
    inline void build(int cur,int l,int r)
    {
        if (l==r)
        {
            ans[cur]=w2[l]%mod;
            return;
        }
        build(leftson,l,mid);
        build(rightson,mid+1,r);
        push_up;
    }
    inline void change(int adl,int adr,int cur,int l,int r,int del)
    {
        if(adl<=l&&r<=adr)
        {
            ans[cur]+=del*(r-l+1)%mod;
            tag[cur]+=del;
            return;
        }
        push_down;
        if (adl<=mid) change(adl,adr,leftson,l,mid,del);
        if (adr>mid) change(adl,adr,rightson,mid+1,r,del);
        push_up;
    }
    
    #define ll long long
    
    ll query(int ql,int qr,int cur,int l,int r)
    {
        if (ql<=l&&r<=qr)
        {
            return ans[cur];
        }
        push_down;
        ll answer=0;
        if (ql<=mid) answer+=query(ql,qr,leftson,l,mid)%mod;
        if (qr>mid) answer+=query(ql,qr,rightson,mid+1,r)%mod;
        return answer%mod;
    }
    //end.
    inline void dfs_fir(int x,int f,int dept)
    {
        dep[x]=dept;
        fa[x]=f;
        siz[x]=1;
        int maxn=-1;
        for (int i=h[x],y;i;i=e[i].nex)
        {
            y=e[i].to;
            if (y==f) continue;
            dfs_fir(y,x,dept+1);
            siz[x]+=siz[y];
            if (siz[y]>maxn)
            {
                son[x]=y;
                maxn=siz[y];
            }
        }
    }
    
    inline void dfs_sec(int x,int ft)
    {
        id[x]=++cnt;
    //	printf("id::%d",cnt);
        w2[cnt]=w1[x];
        top[x]=ft;
        if (!son[x]) return;
        dfs_sec(son[x],ft);
        int y;
        for (int i=h[x];i;i=e[i].nex)
        {
            y=e[i].to;
            if (y==fa[x]||y==son[x]) continue;
            dfs_sec(y,y);
        }
    }
    inline ll query_ans(int x,int y)
    {
        ll answ=0;
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            answ+=query(id[top[x]],id[x],1,1,n)%mod;
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        answ+=query(id[x],id[y],1,1,n);
        
        return answ%mod;
    }
    
    inline void upd_tree(int x,int y,int del)
    {
        del%=mod;
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            change(id[top[x]],id[x],1,1,n,del);
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        change(id[x],id[y],1,1,n,del);
    }
    
    inline ll query_sontree(int x)
    {
        return query(id[x],id[x]+siz[x]-1,1,1,n)%mod;
    }
    
    inline void upd_sontree(int x,int del)
    {
        change(id[x],id[x]+siz[x]-1,1,1,n,del);
    }
    
    
    //////
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&r,&mod);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&w1[i]);
        }
        for (int i=1,x,y;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs_fir(r,0,1);
        dfs_sec(r,r);
        build(1,1,n);
        int q,x,y,z;
        while (m--)
        {
            scanf("%d",&q);
            if (q==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                upd_tree(x,y,z);
                continue;
            }
            if (q==2)
            {
                scanf("%d%d",&x,&y);
                printf("%lld
    ",query_ans(x,y));
                continue;
            }
            if (q==3)
            {
                scanf("%d%d",&x,&y);
                upd_sontree(x,y);
                continue;
            }
            scanf("%d",&x);
            printf("%lld
    ",query_sontree(x));
        }
        return 0;
    }
    

    (因为是模板所以把涉及到的知识点的标签都加上了w)

  • 相关阅读:
    19 C#循环语句的跳过和中断 continue和break
    18 C#中的循环执行 for循环
    一种绝对提高开发水平的方法(推荐英语)
    大数据知识普及
    全链路压测压测报告
    QuickSearch快排
    二分查找
    算法
    基于领域驱动设计的业务中台架构设计
    【科普】Scrum——从橄榄球争球到敏捷开发
  • 原文地址:https://www.cnblogs.com/Kan-kiz/p/10933611.html
Copyright © 2011-2022 走看看