P3178 [HAOI2015]树上操作 的dfs序题解

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

//点修改+树修改,(点->根)链查询
#include<bits/stdc++.h>
#define ll long long
#define rint register int
using namespace std;
const int N=1e6+5;
int n,m,root,cnt,tim;
int h[N],be[N],en[N],dep[N];
ll d[N],s1[N],s2[N],size[N],s[N];
struct edge
{
    int v,nxt;
} e[N<<1];
inline ll read()
{
    ll x=0;
    bool flag=false;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')    flag=true;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return flag?~x+1:x;
}
void add_edge(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].nxt=h[u];
    h[u]=cnt;
}
void dfs(int u,int fat)
{
    dep[u]=dep[fat]+1;
    be[u]=++tim;
    size[u]+=d[u];//记录到根节点的距离 
    for(rint i=h[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v!=fat)
        {
            size[v]+=size[u];
            dfs(v,u);
        }
    }
    en[u]=tim;
}
void add(int x,ll c)
{
	if (x==0) return ;
	for (rint i=x;i<=n;i+=(i&(-i)))
	{
		s[i]+=c;
	}
}
void add1(int x,ll c)//处理s1 记录v的变化 
{
    if(x==0)    return;
    for(rint i=x;i<=n;i+=(i&(-i)))
        s1[i]+=c;
}
void add2(int x,ll c)//处理s2 记录dep的乘积 
{
    if(x==0)    return;
    for(rint i=x;i<=n;i+=(i&(-i)))
        s2[i]+=c;
}
ll sum(int x)
{
	ll ans=0;
	for(rint i=x;i;i-=(i&(-i)))
	{
		ans+=s[i];
	}
	return ans;
}
ll sum1(int x)//求v的和 
{
    ll ans=0;
    for(rint i=x;i;i-=(i&(-i)))
        ans+=s1[i];
    return ans;
}
ll sum2(int x)//求乘积的和 
{
    ll ans=0;
    for(rint i=x;i;i-=(i&(-i)))
        ans+=s2[i];
    return ans;
}
int main()
{
    n=read(),m=read(),root=1;
    for(rint i=1;i<=n;++i)
        d[i]=read();
    for(rint i=1;i<n;++i)
    {
        int x=read(),y=read();
        add_edge(x,y);
        add_edge(y,x);
    }
    dfs(root,0);
    for(rint i=1;i<=m;++i)
    {
        int op=read();//(deep[y]-deep[x]+1)*v=v*(deep[y]+1)-v*deep[x]
        if(op==1)
        {
            int x=read();ll w=read();
            add(be[x],w);add(en[x]+1,-w);//差分记录v 
        }
        if(op==2)
        {
            int x=read();ll w=read();
            add1(be[x],w);add1(en[x]+1,-w);//差分记录v 
            add2(be[x],dep[x]*w);add2(en[x]+1,-dep[x]*w);//差分记录dep*v 
        }
        if(op==3)
        {
            int a=read();
            ll ans=size[a];//先加上原数据 
            ans+=((dep[a]+1)*sum1(be[a])-sum2(be[a]));//子树修改求和 
            ans+=sum(be[a]);//点修改求和 
            printf("%lld\n",ans);
        }
    }
}
/*
in
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
out
6
9
13

*/

  

posted @ 2022-11-22 09:57  心悟&&星际  阅读(31)  评论(0)    收藏  举报