有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
第一行包含两个整数 N, M 。表示点数和操作数。
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
//bzoj4034 单点更新和子树更新求区间 //操作 1 :把某个节点 x 的点权增加 a 。 //操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。 //操作 3 :询问某个节点 x 到根的路径中所有点的点权和。 #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; const int maxn=101010; int tot,p,v,L,R; vector<int>G[maxn]; int siz[maxn],son[maxn],fa[maxn],deep[maxn],top[maxn],id[maxn],pre[maxn]; ll a[maxn]; ll addv[4*maxn]; ll sumv[4*maxn]; void init(int n){ tot=0; for(int i=1;i<=n;i++) G[i].clear(); mem0(addv); mem0(sumv); mem0(pre); } void dfs1(int u,int dep){ deep[u]=dep; siz[u]=1,son[u]=0; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(v==fa[u]) continue; fa[v]=u; dfs1(v,dep+1); if(siz[son[u]]<siz[v]){ son[u]=v; } siz[u]+=siz[v]; } } void dfs2(int u,int tp){ top[u]=tp; id[u]=++tot; pre[u]=id[u]; if(son[u]!=0){ //这里要注意也要更新pre[u]啊,坑了一个小时 dfs2(son[u],tp); pre[u]=max(pre[u],pre[son[u]]); } for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(son[u]==v||v==fa[u]) continue; dfs2(v,v); pre[u]=max(pre[u],pre[v]); } } void pushup(int rt){ sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1]; } void build(int l,int r,int rt){ sumv[rt]=0; if(l==r) return ; int m=(l+r)>>1; build(lson); build(rson); } void pushdown(int rt,int l){ if(addv[rt]!=0){ addv[rt<<1]+=addv[rt]; addv[rt<<1|1]+=addv[rt]; sumv[rt<<1]+=addv[rt]*(l-(l>>1)); sumv[rt<<1|1]+=addv[rt]*(l>>1); addv[rt]=0; } } void update1(int l,int r,int rt){ if(l==r){ sumv[rt]+=v; return ; } int m=(l+r)>>1; pushdown(rt,r-l+1); if(p<=m) update1(lson); else update1(rson); pushup(rt); } void update2(int l,int r,int rt){ if(L<=l&&R>=r){ addv[rt]+=v; sumv[rt]+=(ll)(r-l+1)*v; return ; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update2(lson); if(R>m) update2(rson); pushup(rt); } ll query(int l,int r,int rt){ ll ret=0; if(L<=l&&R>=r){ return sumv[rt]; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) ret+=query(lson); if(R>m) ret+=query(rson); return ret; } ll Query(int u,int v){ ll ret=0; int f1=top[u],f2=top[v]; while(f1!=f2){ if(deep[f1]<deep[f2]){ swap(f1,f2); swap(u,v); } L=id[f1],R=id[u]; ret+=query(1,tot,1); u=fa[f1]; f1=top[u]; } if(deep[u]>deep[v]){ swap(f1,f2); swap(u,v); } L=id[u],R=id[v]; ret+=query(1,tot,1); return ret; } int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ init(n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); int u; for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs1(1,0); dfs2(1,0); build(1,tot,1); for(int i=1;i<=n;i++){ p=id[i],v=a[i]; update1(1,tot,1); } int k; for(int i=1;i<=m;i++){ scanf("%d",&k); if(k==1){ scanf("%d%d",&u,&v); p=id[u]; update1(1,tot,1); } if(k==2){ scanf("%d%d",&u,&v); L=id[u],R=pre[u]; update2(1,tot,1); } if(k==3){ scanf("%d",&u); printf("%lld\n",Query(u,1)); } } } return 0; }