• 树链剖分模板


    树链剖分模板

    如题,已知一棵包含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为根节点的子树内所有节点值之和
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int MAXN = 2e5+10;//点的个数
    struct node{
      int l,r;
      int sum,laze;//线段树
    }tree[MAXN<<2];
    struct edge{
       int next,to;
    }e[MAXN<<1];
    int a[MAXN];
    int head[MAXN];
    int siz[MAXN];//子树的大小
    int top[MAXN];//重链的顶端
    int son[MAXN];//每个节点的重儿子
    int d[MAXN];//每个节点的深度
    int fa[MAXN];//每个节点的父亲节点
    int id[MAXN];//每个节点的DFS序
    int rk[MAXN];//每个DFS序对应的节点
    inline int L(int x){return x<<1;};
    inline int R(int x){return x<<1|1;};
    inline int MID(int l,int r){return (l+r)>>1;};
    int n,m,r,MOD,uu,vv;
    int cnt=0;
    void add(int x,int y){
       e[++cnt].next=head[x];
       e[cnt].to=y;
       head[x]=cnt;
    }
    void dfs1(int u,int f,int depth){
       d[u]=depth;
       fa[u]=f;
       siz[u]=1;  //这个点本身size=1
       for (int i=head[u];i;i=e[i].next){
         int v=e[i].to;
         if (v==f)
            continue;
         dfs1(v,u,depth+1); //层次深度+1
         siz[u]+=siz[v];   //子节点的size已经被处理,用它来更新父亲节点
         if (siz[v]>siz[son[u]])
            son[u]=v;      //选取size最大的作为重儿子并不断更新
       }
    }
    void dfs2(int u,int t){
        top[u]=t;     //标记这个节点,重链顶端
        id[u]=++cnt;  //标记DFS序列
        rk[cnt]=a[u];
        if (!son[u])//如果到根节点
            return;
        dfs2(son[u],t);
        //我们选择有限进入重儿子,让重儿子的DFS序连续
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if (v!=son[u] && v!=fa[u])//如果一个点不是重儿子,并且这个节点也不是其父亲节点
                dfs2(v,v);
        }
    }
    void push_down(int root){
        if (tree[root].laze){
            tree[L(root)].laze+=tree[root].laze;
            tree[R(root)].laze+=tree[root].laze;
            tree[L(root)].sum+=(tree[L(root)].r-tree[L(root)].l+1)*tree[root].laze;
            tree[R(root)].sum+=(tree[R(root)].r-tree[R(root)].l+1)*tree[root].laze;
            tree[L(root)].sum%=MOD;
            tree[R(root)].sum%=MOD;
            tree[root].laze=0;
        }
    }
    void buildtree(int root,int l,int r){
       tree[root].l=l;
       tree[root].r=r;
       if (l==r){
          tree[root].sum=rk[l]%MOD;
          return ;
       }
       int mid=MID(l,r);
       buildtree(L(root),l,mid);
       buildtree(R(root),mid+1,r);
       tree[root].sum=(tree[L(root)].sum+tree[R(root)].sum)%MOD;
    }
    int query(int root,int ql,int qr){
      int l=tree[root].l;
      int r=tree[root].r;
      int res=0;
      if (ql<=l && r<=qr){
        return tree[root].sum;
      }
      push_down(root);
      int mid=MID(l,r);
      if (qr<=mid){
         res=query(L(root),ql,qr);
      }else if (ql>mid){
         res=query(R(root),ql,qr);
      }else {
         res=query(L(root),ql,mid);
         res+=query(R(root),mid+1,qr);
      }
      return res%MOD;
    }
    void update(int root,int ul,int ur,int w){
       int l=tree[root].l;
       int r=tree[root].r;
       if (ul<=l && r<=ur){
          tree[root].laze+=w;
          tree[root].sum+=(r-l+1)*w;
          return ;
       }
       push_down(root);
       int mid=MID(l,r);
       if (ur<=mid){
           update(L(root),ul,ur,w);
       }else if (ul>mid){
           update(R(root),ul,ur,w);
       }else{
           update(L(root),ul,mid,w);
           update(R(root),mid+1,ur,w);
       }
       tree[root].sum=(tree[L(root)].sum+tree[R(root)].sum)%MOD;
    }
    int qRange(int x,int y){
      int ans=0;
      while(top[x]!=top[y]){//不在一条链上
        if (d[top[x]]<d[top[y]])swap(x,y);//把x变成深的节点
        ans+=query(1,id[top[x]],id[x]);//求和
        ans%=MOD;
        x=fa[top[x]];//在跳到链的顶端的上面一个点
      }//直到两个点处于一条链上
      if (d[x]>d[y])swap(x,y);//在同一层后继续
      ans+=query(1,id[x],id[y]);
      return ans%MOD;
    }
    void updRange(int x,int y,int k){
      k%=MOD;
      while(top[x]!=top[y]){
        if (d[top[x]]<d[top[y]])swap(x,y);
        update(1,id[top[x]],id[x],k);
        x=fa[top[x]];
      }
      if (d[x]>d[y])swap(x,y);
      update(1,id[x],id[y],k);
    }
    int qson(int x){
       return query(1,id[x],id[x]+siz[x]-1)%MOD;
    }
    void updson(int x,int k){
    //  cout<<id[x]<<" "<<siz[x]<<endl;
      update(1,id[x],id[x]+siz[x]-1,k);
    }
    int main(){
    
      while(~scanf("%d%d%d%d",&n,&m,&r,&MOD)){
        memset(head,0,sizeof(head));
        memset(id,0,sizeof(id));
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for (int i=1;i<n;i++){
            scanf("%d%d",&uu,&vv);
            add(uu,vv);
            add(vv,uu);
        }
        cnt=0;
        dfs1(r,0,1);
        dfs2(r,r);
        buildtree(1,1,n);
        while(m--){
            int op,x,y,z;
            scanf("%d",&op);
            if (op==1){
                scanf("%d%d%d",&x,&y,&z);
                updRange(x,y,z);
            }else if (op==2){
              scanf("%d%d",&x,&y);
              printf("%d
    ",qRange(x,y));
            }else if (op==3){
              scanf("%d%d",&x,&y);
             // cout<<x<<" "<<y<<endl;
              updson(x,y);
            }else {
              scanf("%d",&x);
              printf("%d
    ",qson(x));
            }
        }
      }
      return 0;
    }
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    DateTime类型的一个Bug
    无痛苦的软件维护——被遗忘的需求
    完全命令行.NET开发
    无痛苦的软件维护——文档和代码
    .NET初学者架构设计指南(一)Hello world的时代
    NGOSS的一点简单概念
    软件的逻辑层次
    VSTS for Testers学习笔记目录
    How Google Tests Software (出书,停止更新)
    推荐——《浪潮之巅》(据传稍后会出书,停止更新)
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11397445.html
Copyright © 2020-2023  润新知