zoukankan      html  css  js  c++  java
  • 洛谷 P3178 [HAOI2015]树上操作

    洛谷 P3178 [HAOI2015]树上操作

    洛谷传送门

    题目描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

    • 操作 1 :把某个节点 x 的点权增加 a 。
    • 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    • 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    输入格式

    第一行包含两个整数 N, M 。表示点数和操作数。
    接下来一行 N 个整数,表示树中节点的初始权值。
    接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。
    再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

    输出格式

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

    输入输出样例

    输入 #1复制

    输出 #1复制

    说明/提示

    对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

    题解:

    树链剖分的模板题。

    其实比模板题目稍微简单了一些。

    如果对树链剖分一窍不通的可以观赏本蒟蒻的这篇博客:

    浅谈树链剖分

    里面对树链剖分有了还算全面的讲解。谢谢大家捧场!

    然后记得开long long

    附上丑陋的AC代码...

    #include<cstdio>
    #include<algorithm>
    #define lson pos<<1
    #define rson pos<<1|1
    #define int long long
    using namespace std;
    const int maxn=1e5+1;
    int n,m,tot,cnt;
    int a[maxn];
    int head[maxn],nxt[maxn<<1],to[maxn<<1];
    int fa[maxn],son[maxn],size[maxn],deep[maxn];
    int top[maxn],id[maxn],w[maxn];
    int tree[maxn<<2],lazy[maxn<<2];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    void dfs1(int x,int f)
    {
        deep[x]=deep[f]+1;
        fa[x]=f;
        size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==f)
                continue;
            dfs1(y,x);
            size[x]+=size[y];
            if(!son[x]||size[y]>size[son[x]])
                son[x]=y;
        }
    }
    void dfs2(int x,int t)
    {
        id[x]=++cnt;
        w[cnt]=a[x];
        top[x]=t;
        if(!son[x])
            return;
        dfs2(son[x],t);
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x]||y==son[x])
                continue;
            dfs2(y,y);
        }
    }
    void build(int pos,int l,int r)
    {
        int mid=(l+r)>>1;
        if(l==r)
        {
            tree[pos]=w[l];
            return;
        }
        build(lson,l,mid);
        build(rson,mid+1,r);
        tree[pos]=tree[lson]+tree[rson];
    }
    void mark(int pos,int l,int r,int k)
    {
        tree[pos]+=(r-l+1)*k;
        lazy[pos]+=k;
    }
    void pushdown(int pos,int l,int r)
    {
        int mid=(l+r)>>1;
        mark(lson,l,mid,lazy[pos]);
        mark(rson,mid+1,r,lazy[pos]);
        lazy[pos]=0;
    }
    void update(int pos,int l,int r,int x,int y,int k)
    {
        int mid=(l+r)>>1;
        if(x<=l && r<=y)
        {
            mark(pos,l,r,k);
            return;
        }
        pushdown(pos,l,r);
        if(x<=mid)
            update(lson,l,mid,x,y,k);
        if(y>mid)
            update(rson,mid+1,r,x,y,k);
        tree[pos]=tree[lson]+tree[rson];
    }
    void upd_subtree(int x,int k)
    {
        update(1,1,n,id[x],id[x]+size[x]-1,k);
    }
    int query(int pos,int l,int r,int x,int y)
    {
        int ret=0;
        int mid=(l+r)>>1;
        if(x<=l && r<=y)
            return tree[pos];
        pushdown(pos,l,r);
        if(x<=mid)
            ret+=query(lson,l,mid,x,y);
        if(y>mid)
            ret+=query(rson,mid+1,r,x,y);
        return ret;
    }
    int q_chain(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,1,n,id[top[x]],id[x]);
            x=fa[top[x]];
        }
        if(deep[x]<deep[y])
            swap(x,y);
        ret+=query(1,1,n,id[y],id[x]);
        return ret;
    }
    signed main()
    {
        // freopen("test.in","r",stdin);
        // freopen("test.out","w",stdout);
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%lld%lld",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs1(1,0);
        dfs2(1,1);
        build(1,1,n);
        while(m--)
        {
            int k,x,z;
            scanf("%lld",&k);
            if(k==1)
            {
                scanf("%lld%lld",&x,&z);
                update(1,1,n,id[x],id[x],z);
            }
            else if(k==2)
            {
                scanf("%lld%lld",&x,&z);
                upd_subtree(x,z);
            }
            else
            {
                scanf("%lld",&x);
                printf("%lld
    ",q_chain(1,x));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法(讲的非常容易理解哦)
    关于splice()方法,slice() 、split()方法讲解,reverse()方法、replace()方法
    js面向对象高级编程
    js面向对象的几种设计模式,以及实现继承的几种方式
    解析Vue2.0和3.0的响应式原理和异同(带源码)
    总结js的几种数据类型检测方法
    javascript中Array常用方法,以及String的常用方法处理
    从输入URL到浏览器显示页面发生了什么,一个完整的http请求过程
    web前端如何防范安全攻击
    前端seo优化总结
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11574178.html
Copyright © 2011-2022 走看看