题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
题解: 直接维护树的欧拉序,将第一次进入的标记为+1,回溯时出去的标记为-1,如此前缀和便是x到根的点权和,每个节点都会在欧拉序中出现两次,第一个操作便是单点修改,第二次操作便是将第一次出现到第二次出现的区间修改,线段树维护即可
#include<bits/stdc++.h>
using namespace std;
#define Sheryang main
const int maxn=2e5+7;
typedef long long ll;
const int mod=1e9+7;
///#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
///char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
#define IO cin.tie(0),ios::sync_with_stdio(false);
#define pi acos(-1)
#define PII pair<ll,ll>
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
/** keep hungry and keep calm! **/
int Time,w[maxn],pos[maxn],n,f[maxn],dfn[maxn],_dfn[maxn],oula[maxn];
vector<int>G[maxn];
void dfs(int u,int fa){
oula[++Time] = u;
dfn[u] = Time;
f[Time] = 1;
int sz = G[u].size();
for(int i = 0 ; i<sz ; i++){
int v = G[u][i];
if(v==fa) continue;
dfs(v,u);
}
oula[++Time] = u;
_dfn[u] = Time;
f[Time] = -1;
}
ll sum[maxn<<4],lazy[maxn<<4],Lazy[maxn<<4],sumf[maxn<<4];
void pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
sumf[rt] = sumf[rt<<1] + sumf[rt<<1|1];
}
void build(int l=1,int r=2*n,int rt=1){
if(l==r){
sum[rt] = w[oula[l]]*f[l];
sumf[rt] = f[l];
return;
}
int mid = l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(int rt){
if(lazy[rt]){
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*sumf[rt<<1];
sum[rt<<1|1] += lazy[rt]*sumf[rt<<1|1];
lazy[rt] = 0;
}
}
void update(int l,int r,int vol,int L=1,int R=2*n,int rt=1){
if(L>=l && R<=r){
sum[rt] += 1LL*vol*sumf[rt];
lazy[rt] += vol;
pushdown(rt);
return;
}
pushdown(rt);
int mid = L+R>>1;
if(l<=mid){
update(l,r,vol,L,mid,rt<<1);
}
if(r>mid){
update(l,r,vol,mid+1,R,rt<<1|1);
}
pushup(rt);
}
ll query(int l,int r,int L=1,int R=2*n,int rt=1){
if(L>=l && R<=r){
return sum[rt];
}
pushdown(rt);
int mid = L+R>>1;
ll ans = 0;
if(l<=mid){
ans += query(l,r,L,mid,rt<<1);
}
if(r>mid){
ans += query(l,r,mid+1,R,rt<<1|1);
}
return ans;
}
int Sheryang(){
n=read;
int m=read;
for(int i=1;i<=n;i++){
w[i] = read;
}
for(int i=1;i<n;i++){
int u=read,v=read;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
build();
for(int i=0;i<m;i++){
int op=read;
if(op==1){
int x=read,vol=read;
update(dfn[x],dfn[x],vol);
update(_dfn[x],_dfn[x],vol);
}else if(op==2){
int x=read,vol=read;
update(dfn[x],_dfn[x],vol);
}else{
int x=read;
printf("%lld\n",query(1,dfn[x]));
}
}
return 0;
}
// 1
// 2 4
// 3 5