zoukankan      html  css  js  c++  java
  • 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: 复制
    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3
    输出样例#1: 复制
    6
    9
    13

    说明

    对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

    会超过 10^6 。

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const int N=1e5+5;
    
    int n,m;
    int w[N];
    int opt,x,a;
    int head[N],num_edge;
    struct Edge
    {
        int v,nxt;
    }edge[N<<1];
    struct Node
    {
        int fa,son;
        int size;
        int top;
        int s,t;
        int dep;
    }node[N];
    struct TREE
    {
        TREE *lson,*rson;
        int l,r,mid;
        long long sum,addval;
    }tree[N<<2];
    
    typedef TREE* Tree;
    Tree now_node=tree,Root;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=c=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    inline void add_edge(int u,int v)
    {
        edge[++num_edge].v=v;
        edge[num_edge].nxt=head[u];
        head[u]=num_edge;
    }
    
    void dfs1(int u)
    {
        node[u].size=1;
        for(int i=head[u],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            if(v==node[u].fa)
                continue;
            node[v].fa=u;
            node[v].dep=node[u].dep+1;
            dfs1(v);
            node[u].size+=node[v].size;
            if(node[v].size>node[node[u].son].size)
                node[u].son=v;
        }
    }
    
    int bound;
    void dfs2(int u,int top)
    {
        node[u].s=++bound;
        node[u].top=top;
        if(node[u].son)
        {
            dfs2(node[u].son,top);
            for(int i=head[u],v;i;i=edge[i].nxt)
            {
                v=edge[i].v;
                if(v==node[u].fa||v==node[u].son)
                    continue;
                dfs2(v,v);
            }
        }
        node[u].t=bound;
    }
    
    void build(Tree &root,int l,int r)
    {
        root=++now_node;
        root->l=l,root->r=r,root->mid=l+r>>1;
        if(l==r)
            return;
        build(root->lson,l,root->mid);
        build(root->rson,root->mid+1,r);
    }
    
    inline void pushdown(Tree root)
    {
        if(root->addval)
        {
            root->lson->addval+=root->addval;
            root->rson->addval+=root->addval;
            root->lson->sum+=(root->lson->r-root->lson->l+1)*root->addval;
            root->rson->sum+=(root->rson->r-root->rson->l+1)*root->addval;
            root->addval=0;
        }
    }
    
    void update(const Tree &root,int l,int r,int k)
    {
        if(l==root->l&&root->r==r)
        {
            root->sum+=(r-l+1)*1LL*k;
            root->addval+=k;
            return;
        }
        pushdown(root);
        if(r<=root->mid)
            update(root->lson,l,r,k);
        else if(l>root->mid)
            update(root->rson,l,r,k);
        else
        {
            update(root->lson,l,root->mid,k);
            update(root->rson,root->mid+1,r,k);
        }
        root->sum=root->lson->sum+root->rson->sum;
    }
    
    long long query(Tree root,int l,int r)
    {
        if(l<=root->l&&root->r<=r)
            return root->sum;
        pushdown(root);
        if(r<=root->mid)
            return query(root->lson,l,r);
        else if(l>root->mid)
            return query(root->rson,l,r);
        else
            return query(root->lson,l,root->mid)+query(root->rson,root->mid+1,r);
    }
    
    inline long long Query(int x)
    {
        int fx=node[x].top;
        long long ans=0;
        while(fx!=1)
        {
            ans+=query(Root,node[fx].s,node[x].s);
            x=node[fx].fa;
            fx=node[x].top;
        }
        return ans+query(Root,node[1].s,node[x].s);
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;++i)
            w[i]=read();
        for(int i=1,u,v;i<n;++i)
        {
            u=read(),v=read();
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs1(1);
        dfs2(1,1);
        build(Root,1,n);
        for(int i=1;i<=n;++i)
            update(Root,node[i].s,node[i].s,w[i]);
        while(m--)
        {
            opt=read();
            if(opt==1)
            {
                x=read(),a=read();
                update(Root,node[x].s,node[x].s,a);
            }
            else if(opt==2)
            {
                x=read(),a=read();
                update(Root,node[x].s,node[x].t,a);
            }
            else
            {
                x=read();
                printf("%lld
    ",Query(x));
            }
        }
        return 0;
    }
  • 相关阅读:
    红黑树数据结构剖析
    miniui表单验证守则总结
    常用的JS页面跳转代码调用大全
    Jsp页面跳转和js控制页面跳转的几种方法
    处理和引发事件
    HeaderHandler 委托
    序列化SoapFormatter
    Debug.Assert
    C#的Thread类
    再次学习线程概念
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8544598.html
Copyright © 2011-2022 走看看