题目链接
题意:
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
直接跑树链剖分,我们知道剖分的第二个dfs,我的代码是getpos
中,某一个节点的子树节点编号是连续的,所以第二个操作区间就是
[p[u],p[u]+size[u]-1]
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
#define fastIO ios::sync_with_stdio(false);cin.tie(0);
#define ll long long
#define pb push_back
#define gcd __gcd
#define For(i,j,k) for(int i=(j);i<=k;i++)
#define lowbit(i) (i&(-i))
#define _(x) printf("%d\n",x)
typedef vector<ll> vec;
typedef pair<int,int> PI;
const double EPS = 1e-8;
const int maxn = 2e5+100;
const int inf = 1 << 28;
int n,m;
struct Edge{
int to,next;
}es[maxn<<1];
int head[maxn],tot;
void addEdge(int u,int v){
es[tot].to=v;es[tot].next=head[u];head[u]=tot++;
}
ll a[maxn];
int num[maxn],p[maxn],fp[maxn],fa[maxn],son[maxn],top[maxn],deep[maxn],pos;
void init(){
tot=0;
pos=1;
cl(head,-1);
cl(son,-1);
}
void dfs(int u,int pre,int d){
num[u]=1;
deep[u]=d;
fa[u]=pre;
for(int i=head[u];~i;i=es[i].next){
int v=es[i].to;
if(v!=pre){
dfs(v,u,d+1);
num[u]+=num[v];
if(son[u]==-1||num[son[u]]<num[v])son[u]=v;
}
}
}
void getpos(int u,int sp){
top[u]=sp;
p[u]=pos++;
fp[p[u]]=u;
if(son[u]==-1)return;
getpos(son[u],sp);
for(int i=head[u];~i;i=es[i].next){
int v=es[i].to;
if(v!=fa[u]&&v!=son[u])getpos(v,v);
}
}
/
ll sum[maxn<<2],lazy[maxn<<2];
void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int l,int r){
if(lazy[rt]){
int mid=l+r>>1;
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
sum[rt<<1]+=lazy[rt]*(mid-l+1);
sum[rt<<1|1]+=lazy[rt]*(r-mid);
lazy[rt]=0;
}
}
void build(int rt,int l,int r){
lazy[rt]=0;
if(l==r){
sum[rt]=a[fp[l]];
return ;
}
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int x,int y,ll val){
if(x<=l&&r<=y){
sum[rt]+=val*(r-l+1);
lazy[rt]+=val;return ;
}
pushdown(rt,l,r);
int mid=l+r>>1;
if(x<=mid)update(rt<<1,l,mid,x,y,val);
if(y>mid)update(rt<<1|1,mid+1,r,x,y,val);
pushup(rt);
}
ll query(int rt,int l,int r,int x,int y){
if(x<=l&&r<=y){
return sum[rt];
}
pushdown(rt,l,r);
int mid=l+r>>1;
ll ans=0;
if(x<=mid)ans+=query(rt<<1,l,mid,x,y);
if(y>mid)ans+=query(rt<<1|1,mid+1,r,x,y);
return ans;
}
ll findsum(int u,int v){
ll ans=0;
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]])swap(u,v);
ans+=query(1,1,pos-1,p[top[u]],p[u]);
u=fa[top[u]];
}
if(deep[u]>deep[v])swap(u,v);
return ans+query(1,1,pos-1,p[u],p[v]);
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=0;i<n-1;i++){
int u,v;scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
dfs(1,0,0);getpos(1,1);
build(1,1,pos-1);
while(m--){
int op,x,y;
scanf("%d%d",&op,&x);
if(op==1){
ll val;scanf("%lld",&val);
update(1,1,pos-1,p[x],p[x],val);
}
else if(op==2){
ll v;scanf("%lld",&v);
update(1,1,pos-1,p[x],p[x]+num[x]-1,v);
}
else {
printf("%lld\n",findsum(1,x));//if(m)printf("\n");
}
}
}
return 0;
}
/*
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
*/