題意: 有一棵點數爲 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