做的时候经验不够,没有想到一种类似于差分的思想
观察操作:
操作一:单点修改,对子树影响:所有子树节点到根路径加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;
}区间修改区间查询,写复杂了两颗线段树码量不敢想象

京公网安备 11010502036488号