做的时候经验不够,没有想到一种类似于差分的思想
观察操作:
操作一:单点修改,对子树影响:所有子树节点到根路径加a
操作二:子树所有节点增加a,可以看作先将所有节点到根的总权值加上a * dep[u],再减去a *
(dep[x]-1),数据结构维护一下即可
操作三:直接查询
Code:
#include<bits/stdc++.h> #define ll long long using namespace std; struct segmenttree { ll l,r,v,lazy,len; }sgt1[8*100000+5],sgt2[8*100000+5]; ll lt[100005],nt[200005],ed[200005],val[100005],in[100005],out[100005],dep[100005],rk[100005],n,m,cnt,visittime; void addedge(ll x,ll y) { ed[++cnt]=y;nt[cnt]=lt[x];lt[x]=cnt; } void build1(ll p,ll l,ll r) { sgt1[p].l=l;sgt1[p].r=r;sgt1[p].len=r-l+1; if(l==r)return ; ll mid=(l+r)>>1; build1(p<<1,l,mid); build1(p<<1|1,mid+1,r); } void build2(ll p,ll l,ll r) { sgt2[p].l=l;sgt2[p].r=r;sgt2[p].len=r-l+1; if(l==r)return ; ll mid=(l+r)>>1; build2(p<<1,l,mid); build2(p<<1|1,mid+1,r); } void spread1(ll p) { ll v=sgt1[p].lazy;sgt1[p].lazy=0; sgt1[p<<1].v+=sgt1[p<<1].len*v; sgt1[p<<1|1].v+=sgt1[p<<1|1].len*v; sgt1[p<<1].lazy+=v;sgt1[p<<1|1].lazy+=v; } void update1(ll p) { sgt1[p].v=sgt1[p<<1].v+sgt1[p<<1|1].v; } void change1(ll p,ll l,ll r,ll d) { if(sgt1[p].r<l||sgt1[p].l>r)return ; if(sgt1[p].lazy)spread1(p); if(l<=sgt1[p].l&&sgt1[p].r<=r) { sgt1[p].v+=sgt1[p].len*d; sgt1[p].lazy+=d; return ; } change1(p<<1,l,r,d); change1(p<<1|1,l,r,d); update1(p); } void spread2(ll p) { ll v=sgt2[p].lazy;sgt2[p].lazy=0; sgt2[p<<1].v+=sgt2[p<<1].len*v; sgt2[p<<1|1].v+=sgt2[p<<1|1].len*v; sgt2[p<<1].lazy+=v;sgt2[p<<1|1].lazy+=v; } void update2(ll p) { sgt2[p].v=sgt2[p<<1].v+sgt2[p<<1|1].v; } void change2(ll p,ll l,ll r,ll d) { if(sgt2[p].r<l||sgt2[p].l>r)return ; if(sgt2[p].lazy)spread2(p); if(l<=sgt2[p].l&&sgt2[p].r<=r) { sgt2[p].v+=sgt2[p].len*d; sgt2[p].lazy+=d; return ; } change2(p<<1,l,r,d); change2(p<<1|1,l,r,d); update2(p); } ll getcnt1(ll p,ll l,ll r) { if(sgt1[p].r<l||sgt1[p].l>r)return 0; if(l<=sgt1[p].l&&sgt1[p].r<=r)return sgt1[p].v; if(sgt1[p].lazy)spread1(p); return getcnt1(p<<1,l,r)+getcnt1(p<<1|1,l,r); } ll getcnt2(ll p,ll l,ll r) { if(sgt2[p].r<l||sgt2[p].l>r)return 0; if(l<=sgt2[p].l&&sgt2[p].r<=r)return sgt2[p].v; if(sgt2[p].lazy)spread2(p); return getcnt2(p<<1,l,r)+getcnt2(p<<1|1,l,r); } void dfs(ll u,ll fa,ll dis) { in[u]=++visittime;dep[u]=dep[fa]+1;rk[visittime]=u; change2(1,in[u],in[u],dis+val[u]); ll i; for(i=lt[u];i;i=nt[i]) { ll v=ed[i]; if(v==fa)continue; dfs(v,u,dis+val[u]); } out[u]=visittime; } int main() { scanf("%lld%lld",&n,&m); ll i; for(i=1;i<=n;i++)scanf("%lld",&val[i]); for(i=1;i<n;i++) { ll x,y; scanf("%lld%lld",&x,&y); addedge(x,y); addedge(y,x); } build1(1,1,n);build2(1,1,n);dfs(1,0,0); while(m--) { ll op,x; scanf("%lld%lld",&op,&x); if(op==3)printf("%lld\n",getcnt1(1,in[x],in[x])*dep[x]+getcnt2(1,in[x],in[x])); else { ll a; scanf("%lld",&a); if(op==1)change2(1,in[x],out[x],a); else { change1(1,in[x],out[x],a); change2(1,in[x],out[x],-(dep[x]-1)*a); } } } return 0; }
区间修改区间查询,写复杂了两颗线段树码量不敢想象