树剖+线段树
要能够一次性给子树赋值,可以用DFS序+线段树
要查询点到根的路径和,树剖+线段树
于是用树剖的DFS序建树
#include<cstdio>
#define N 100005
#define ll long long
using namespace std;
struct edge{int next,to;}e[N<<1];
struct segment_tree{int l, r; ll sum, lazy;}t[5*N];
ll v[N];
int ecnt=0, last[N], siz[N], dep[N], top[N], fa[N], son[N], cnt=0, pos[N], repos[N];
void add_edge(int a, int b)
{
e[++ecnt]=(edge){last[a],b};
last[a]=ecnt;
}
void dfs1(int x)
{
dep[x]=dep[fa[x]]+1;
siz[x]=1;
for(int i = last[x]; i; i=e[i].next)
{
int y=e[i].to;
if(y==fa[x])continue;
fa[y]=x;
dfs1(y);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])
son[x]=y;
}
}
void dfs2(int x)
{
pos[x]=++cnt;
repos[cnt]=x;
if(son[fa[x]]==x)top[x]=top[fa[x]];
else top[x]=x;
if(son[x])dfs2(son[x]);
for(int i = last[x]; i; i=e[i].next)
{
int y=e[i].to;
if(y==fa[x] || y==son[x])continue;
dfs2(y);
}
}
void maintain(int x)
{
if(!t[x].lazy || t[x].l==t[x].r)return;
t[x<<1].lazy+=t[x].lazy;
t[x<<1|1].lazy+=t[x].lazy;
t[x<<1].sum+=t[x].lazy*(t[x<<1].r-t[x<<1].l+1);
t[x<<1|1].sum+=t[x].lazy*(t[x<<1|1].r-t[x<<1|1].l+1);
t[x].lazy=0;
}
void build(int x, int l, int r)
{
t[x].l=l;
t[x].r=r;
t[x].lazy=0;
if(l==r)
{
t[x].sum=v[repos[l]];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
}
void update(int x, int p, int v)
{
maintain(x);
if(t[x].l==t[x].r)
{
t[x].sum+=v;
return;
}
int mid=(t[x].l+t[x].r)>>1;
if(p<=mid)update(x<<1,p,v);
else update(x<<1|1,p,v);
t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
}
void change(int x, int l, int r, int v)
{
maintain(x);
if(l<=t[x].l && t[x].r<=r)
{
t[x].lazy=v;
t[x].sum+=1ll*v*(t[x].r-t[x].l+1);
return;
}
int mid=(t[x].l+t[x].r)>>1;
if(l<=mid)change(x<<1,l,r,v);
if(mid+1<=r)change(x<<1|1,l,r,v);
t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
}
ll query(int x, int l, int r)
{
maintain(x);
if(l<=t[x].l && t[x].r<=r)
return t[x].sum;
ll ret=0;
int mid=(t[x].l+t[x].r)>>1;
if(l<=mid)ret+=query(x<<1,l,r);
if(mid+1<=r)ret+=query(x<<1|1,l,r);
return ret;
}
int main()
{
int n, m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%lld",&v[i]);
for(int i = 1, a, b; i < n; i++)
{
scanf("%d%d",&a,&b);
add_edge(a,b);
add_edge(b,a);
}
dfs1(1);
dfs2(1);
build(1,1,n);
while(m--)
{
int cmd;
scanf("%d",&cmd);
if(cmd==1)
{
int x, a;
scanf("%d%d",&x,&a);
update(1,pos[x],a);
}
else if(cmd==2)
{
int x, a;
scanf("%d%d",&x,&a);
change(1,pos[x],pos[x]+siz[x]-1,a);
}
else
{
ll ans=0;
int x;
scanf("%d",&x);
while(x)
{
ans+=query(1,pos[top[x]], pos[x]);
x=fa[top[x]];
}
printf("%lld\n",ans);
}
}
}