• [HAOI2015]树上操作


    [HAOI2015]树上操作https://www.luogu.org/problemnew/show/P3178

    题目描述

    有一棵点数为 (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) ) 。

    输出格式:

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

    输入样例:

    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

    输出样例:

    6
    9
    13

    说明

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


    树剖模板题,要连双向边.
    单点修改(+)子树(区间)修改
    区间查询(根节点到其它节点)

    #define RG register
    #define LL long long
    #include<cstdio>
    using namespace std;
    const int N=1e5+5;
    inline LL read()
    {
        RG LL x=0,w=1;RG char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    LL n,m,cnt,ct;
    LL last[N],val[N],fa[N],top[N],size[N],dfn[N],rk[N],son[N];
    LL sum[N<<2],lazy[N<<2];
    struct edge{LL to,next;}e[N<<1];
    void insert(LL u,LL v)
    {
        e[++cnt]=(edge){v,last[u]};last[u]=cnt;
        e[++cnt]=(edge){u,last[v]};last[v]=cnt;
    }
    void dfs1(LL now)
    {
        size[now]=1;
        for(RG LL i=last[now];i;i=e[i].next)
        {
            LL v=e[i].to;
            if(v==fa[now])continue;
            fa[v]=now;
            dfs1(v);
            size[now]+=size[v];
            if(size[v]>size[son[now]])son[now]=v;
        }
    }
    void dfs2(LL now,LL tp)
    {
        top[now]=tp;dfn[now]=++ct;rk[ct]=now;
        if(son[now])dfs2(son[now],tp);
        for(RG LL i=last[now];i;i=e[i].next)
        {
            LL v=e[i].to;
            if(v==son[now]||v==fa[now])continue;
            dfs2(v,v);
        }
    }
    inline void Pushup(LL root){sum[root]=sum[root<<1]+sum[root<<1|1];}
    void Build(LL root,LL l,LL r)
    {
        if(l==r){sum[root]=val[rk[l]];return;}
        LL mid=(l+r)>>1;
        Build(root<<1,l,mid);
        Build(root<<1|1,mid+1,r);
        Pushup(root);
    }
    inline void Pushdown(LL root,LL len)//len为区间长度
    {
        if(!lazy[root])return;
        lazy[root<<1]+=lazy[root];
        lazy[root<<1|1]+=lazy[root];
        sum[root<<1]+=lazy[root]*(len-(len>>1));
        sum[root<<1|1]+=lazy[root]*(len>>1);
        lazy[root]=0;
    }
    void Modify(LL root,LL l,LL r,LL ll,LL rr,LL k)
    {
        if(ll<=l&&r<=rr)
        {
            sum[root]+=k*(r-l+1);
            lazy[root]+=k;
            return;
        }
        Pushdown(root,r-l+1);
        LL mid=(l+r)>>1;
        if(ll<=mid)Modify(root<<1,l,mid,ll,rr,k);
        if(mid<rr) Modify(root<<1|1,mid+1,r,ll,rr,k);
        Pushup(root);
    }
    LL Query(LL root,LL l,LL r,LL ll,LL rr)
    {
        if(ll<=l&&r<=rr)return sum[root];
        Pushdown(root,r-l+1);
        LL mid=(l+r)>>1,Sum=0;
        if(ll<=mid)Sum+=Query(root<<1,l,mid,ll,rr);
        if(mid<rr)Sum+=Query(root<<1|1,mid+1,r,ll,rr);
        return Sum;
    }
    inline LL Query_Tree(LL now)
    {
        LL Sum=0;
        while(now)//直到fa[top[now]]==0结束,表示top[now]==1-->根节点
        {
            Sum+=Query(1,1,n,dfn[top[now]],dfn[now]);
            now=fa[top[now]];
        }
        return Sum;
    }
    int main()
    {
        n=read();
        m=read();
        for(RG LL i=1;i<=n;i++)val[i]=read();
        for(RG LL i=1;i<n;i++)
        {
            int a=read(),b=read();
            insert(a,b);
        }
        dfs1(1);
        dfs2(1,1);
        Build(1,1,n);
        RG LL act,x,a;
        while(m--)
        {
            act=read();
            if(act==1)
            {
                x=read(),a=read();
                Modify(1,1,n,dfn[x],dfn[x],a);
            }
            if(act==2)
            {
                x=read(),a=read();
                Modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a);
            }
            if(act==3)
            {
                x=read();
                printf("%lld
    ",Query_Tree(x));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    memset
    无穷大无穷小的表示方法
    堆-STL
    3386 二分图 洛谷luogu [模版]
    jquery——幻灯片(只动一屏)
    jquery——整屏滚动
    jquery——元素节点操作
    jquery——事件冒泡、事件委托
    jquery——解决鼠标移入移出导致盒子不停移动的bug
    jquery——无缝滚动
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/8468949.html
Copyright © 2020-2023  润新知