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

    题目描述

    如题,已知一棵包含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为根节点的子树内所有节点值之和

    输入格式

    第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

    接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

    接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

    接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

    操作1: 1 x y z

    操作2: 2 x y

    操作3: 3 x z

    操作4: 4 x

    输出格式

    输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

    输入输出样例

    输入 #1
    5 5 2 24
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    输出 #1
    2
    21
    
    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn=1e5+100;
    struct edge
    {
        int v,next;
    } e[maxn*2];
    struct Tree
    {
        int sum,l,r,lazy;
    } tree[maxn*4];
    
    int top[maxn],tim,dfn[maxn],son[maxn],w[maxn],head[maxn],a[maxn],siz[maxn],deep[maxn],fa[maxn],mod,t;
    
    void add(int u,int v)
    {
        t++;
        e[t].v=v;
        e[t].next=head[u];
        head[u]=t;
    }
    
    void pushup(int rt)
    {
        tree[rt].sum=(tree[rt<<1].sum+tree[rt<<1|1].sum)%mod;
    }
    
    void pushdown(int rt,int l,int r)
    {
        if (tree[rt].lazy==0)
            return;
        int mid=(l+r)>>1;
        tree[rt<<1].lazy+=tree[rt].lazy;
        tree[rt<<1|1].lazy+=tree[rt].lazy;
        tree[rt<<1].sum=(tree[rt<<1].sum+tree[rt].lazy*(mid-l+1))%mod;
        tree[rt<<1|1].sum=(tree[rt<<1|1].sum+tree[rt].lazy*(r-mid))%mod;
        tree[rt].lazy=0;
    }
    
    void build(int rt,int l,int r)
    {
        tree[rt].l=l;
        tree[rt].r=r;
        tree[rt].sum=0;
        if (l==r)
        {
            tree[rt].sum=w[l];
            return;
        }
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);
        build (rt<<1|1,mid+1,r);
        pushup(rt);
    }
    
    void update(int rt,int l,int r,int z)
    {
        if (l<=tree[rt].l&&tree[rt].r<=r)
        {
            tree[rt].lazy+=z;
            tree[rt].sum+=z*(tree[rt].r-tree[rt].l+1);
            return;
        }
        pushdown(rt,tree[rt].l,tree[rt].r);
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if (l<=mid)
        {
            update(rt<<1,l,r,z);
        }
        if (r>mid)
        {
            update(rt<<1|1,l,r,z);
        }
        pushup(rt);
    }
    void dfs1(int u,int f)
    {
        deep[u]=deep[f]+1;
        siz[u]=1;
        fa[u]=f;
        int maxsiz=-1;
        for (int i=head[u]; i; i=e[i].next)
        {
            int v=e[i].v;
            if (v==f)
            {
                continue;
            }
            dfs1(v,u);
            siz[u]+=siz[v];
            if (siz[v]>maxsiz)
            {
                maxsiz=siz[v];
                son[u]=v;
            }
        }
    }
    
    int query(int rt,int l,int r)
    {
        if (l<=tree[rt].l&&tree[rt].r<=r)
        {
            return tree[rt].sum%mod;
        }
        pushdown(rt,tree[rt].l,tree[rt].r);
        int ret=0;
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if (l<=mid)
            ret=(ret+query(rt<<1,l,r))%mod;
        if (r>mid)
            ret=(ret+query(rt<<1|1,l,r))%mod;
        return ret;
    }
    
    void dfs2(int u,int Top)
    {
        dfn[u]=++tim;
        w[tim]=a[u];
        top[u]=Top;
        if (!son[u])
        {
            return;
        }
        dfs2(son[u],Top);
        for (int i=head[u]; i; i=e[i].next)
        {
            int v=e[i].v;
            if (v==fa[u]||v==son[u])
            {
                continue;
            }
            dfs2(v,v);
        }
    }
    
    void update1(int x,int y,int z)
    {
        z=z%mod;
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]])
            {
                swap(x,y);
            }
            update(1,dfn[top[x]],dfn[x],z);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y])
        {
            swap(x,y);
        }
        update(1,dfn[x],dfn[y],z);
    }
    
    int query1(int x,int y)
    {
        int ret=0;
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]])
            {
                swap(x,y);
            }
            ret+=query(1,dfn[top[x]],dfn[x]);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y])
        {
            swap(x,y);
        }
        ret+=query(1,dfn[x],dfn[y]);
        return ret%mod;
    }
    
    int main()
    {
        // freopen("1.txt","w",stdout);
        int n,m,r;
        scanf("%d%d%d%d",&n,&m,&r,&mod);
        for (int i=1; i<=n; ++i)
        {
            scanf("%d",&a[i]);
        }
        for (int i=1,u,v; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs1(r,0);
        dfs2(r,r);
        build(1,1,n);
    
        while (m--)
        {
            int op;
            scanf("%d",&op);
            if (op==1)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                update1(x,y,z);
            }
            if (op==2)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%d
    ",query1(x,y));
            }
            if (op==3)
            {
                int x,z;
                scanf("%d%d",&x,&z);
                update(1,dfn[x],dfn[x]+siz[x]-1,z);
            }
            if (op==4)
            {
                int x;
                scanf("%d",&x);
                printf("%d
    ",query(1,dfn[x],dfn[x]+siz[x]-1));
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    移动及pc端实现签名功能
    中文字符长度与英文字符长度的计算
    IE8部分兼容问题及解决方法
    如何本地搭建手机可访问的web网页
    MYSQL索引的作用和创建
    HTTP协议
    data.json
    axios
    axios基本用法
    Component 初识组件
  • 原文地址:https://www.cnblogs.com/Accpted/p/11356004.html
Copyright © 2011-2022 走看看