• 洛谷3384


    树链剖分:

    fa[ ]父亲节点;son[ ]重儿子节点;siz[ ]以该点为根的子树的大小;

    id[ ]该点在两次dfs后形成序列中的位置;dep[ ]该点深度;

    wt[ ]两次dfs后形成的序列;top[ ]该点所在链的链头

    1.dfs1先求出每个点的深度,父亲节点和以该点为根的子树的大小,并找到其重儿子(及siz最大的儿子)

    2.dfs2求出最终形成的序列,并求出每个点所在链的链头(对于一个点,优先遍历重儿子,保证重链在序列中的连续)

    3.对形成的序列建议可先段树

    3.操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

       先将x,y整条链整条链

    的往上跳,直到他们跳到同一条链上,过程中求出每次跳动区间的和,再求出同一条链中的他们之间的值(此时能够保证是最短路,否则他们之前必然能跳到同一条链上)

    4.操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和,类似操作1

    5.操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

     一棵子树的点在序列中必然连续,又已知其siz,则该棵树上的点的区间为【id[x],id[x]+siz[x]-1】

    6.操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

    同操作3

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #define Rint register int
    #define mid ((l+r)>>1)
    #define lson rt<<1,l,mid
    #define rson rt<<1|1,mid+1,r
    using namespace std; 
    const int maxn=200005;
    int n,m,r,mo,ne,res=0,cnt,laz[maxn<<2],w[maxn],fa[maxn],siz[maxn],dep[maxn],tr[maxn<<2],top[maxn],wt[maxn],id[maxn],to[maxn],nex[maxn],head[maxn],son[maxn];
    
    inline void add(int x,int y){
        to[++ne]=y;nex[ne]=head[x];head[x]=ne;
    }
    
    inline void read(int &x){
        char ch=getchar();x=0;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    }
    
    inline void pushdown(int rt,int len){
        if(laz[rt]==0)return;
        laz[rt<<1]+=laz[rt];laz[rt<<1|1]+=laz[rt];
        tr[rt<<1]+=laz[rt]*(len-(len>>1));tr[rt<<1|1]+=laz[rt]*(len>>1);
        tr[rt<<1]%=mo;tr[rt<<1|1]%=mo;
        laz[rt]=0;
    }
    
    inline void build(int rt,int l,int r){
        if(l==r){tr[rt]=wt[l]%mo;return;}
        build(lson);build(rson);
        tr[rt]=(tr[rt<<1]+tr[rt<<1|1])%mo;
    }
    
    inline void query(int rt,int l,int r,int L,int R){
        if(l>=L&&r<=R){res+=tr[rt];res%=mo;return;}
        pushdown(rt,r-l+1);
        if(mid>=L)query(lson,L,R);
        if(mid<R)query(rson,L,R);
    }
    
    inline void updata(int rt,int l,int r,int L,int R,int k){
        if(l>=L&&r<=R){laz[rt]+=k;tr[rt]+=k*(r-l+1);return;}
        pushdown(rt,r-l+1);
        if(mid>=L)updata(lson,L,R,k);
        if(mid<R)updata(rson,L,R,k);
        tr[rt]=(tr[rt<<1]+tr[rt<<1|1])%mo;
    }
    
    inline int qRange(int x,int y){
        int ans=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            res=0;
            query(1,1,n,id[top[x]],id[x]);
            ans+=res;ans%=mo;x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        res=0;
        query(1,1,n,id[x],id[y]);
        ans+=res;
        return ans%mo;
    }
    
    inline void updRange(int x,int y,int k){//同上 
        k%=mo;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            updata(1,1,n,id[top[x]],id[x],k);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        updata(1,1,n,id[x],id[y],k);
    }
    
    inline void updson(int x,int k){
        updata(1,1,n,id[x],id[x]+siz[x]-1,k);
    }
    
    inline int qson(int x){
        res=0;
        query(1,1,n,id[x],id[x]+siz[x]-1);return res;
    }
    
    inline void dfs1(int x,int f,int depth){
        dep[x]=depth;fa[x]=f;siz[x]=1;
        int maxson=-1;
        for(Rint i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==f)continue;
            dfs1(y,x,depth+1);
            siz[x]+=siz[y];
            if(siz[y]>maxson){son[x]=y;maxson=siz[y];}
        }
    }
    
    inline void dfs2(int x,int topf){
         id[x]=++cnt;
         wt[cnt]=w[x];
         top[x]=topf;
         if(!son[x])return;
         dfs2(son[x],topf);
         for(Rint i=head[x];i;i=nex[i]){
             int y=to[i];
             if(y==fa[x]||y==son[x])continue;
             dfs2(y,y);
         }
    } 
    
    int main(){
        read(n);read(m);read(r);read(mo);
        for(Rint i=1;i<=n;i++)read(w[i]);
        for(Rint i=1;i<n;i++){
            int a,b;read(a);read(b);
            add(a,b);add(b,a);
        }
        dfs1(r,0,1);dfs2(r,r);
        build(1,1,n);
        while(m--){
            int typ,x,y,z;
            read(typ);read(x);
            switch(typ){
                case 1:read(y);read(z);updRange(x,y,z);break;
                case 2:read(y);
                printf("%d\n",qRange(x,y));break;
                case 3:read(y);updson(x,y);break;
                case 4:printf("%d\n",qson(x));break;
            }
        }
    }

    树链剖分代码虽长,但思路非常清晰,思想也容易理解。

  • 相关阅读:
    爱因斯坦IQ题
    微软操作系统的版本分类方法
    C++的辅助工具介绍
    让Dictionary key 支持自定义对象
    正则表达式匹配可能包括任意长度的任意空白的任意字符串(最短匹配)
    linq 对象转换
    "System.Data.SqlServerCe.SqlCeException: 数据库文件大于配置的最大数据库大小。该设置仅在第一次并发数据库连接后生效"解决方案
    Windows XP远程桌面端口更改
    Unicode与UTF8互转(C语言实现)
    VS2005+WinXPDDK+DDKWizard配置驱动开发环境
  • 原文地址:https://www.cnblogs.com/MikuKnight/p/8893970.html
Copyright © 2020-2023  润新知