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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//点修改+树修改,(点->根)链查询
#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 @   心悟&&星际  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示