[BZOJ 4034][HAOI2015]树上操作(欧拉序列+线段树)
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Solution
本来是一道裸的树剖,不过其实是可以欧拉序列搞一搞的
对于每个节点在dfs序中记录2次,入栈的时候加上,出栈的时候减去
那么一个点到根的路径上的信息就是dfs序里它第一次出现的位置的前缀和
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #define MAXN 100005 using namespace std; typedef long long LL; int n,m,w[MAXN],head[MAXN],cnt=0,q[MAXN*2],in[MAXN],out[MAXN],dfn_clock=0; struct Node1 { int next,to; }Edges[MAXN*2]; struct Node2 { int l,r,num; LL sum,lazy; }t[MAXN*8]; int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } void addedge(int u,int v) { Edges[++cnt].next=head[u]; head[u]=cnt; Edges[cnt].to=v; } void dfs(int u,int f) { q[++dfn_clock]=u;in[u]=dfn_clock; for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(v==f)continue; dfs(v,u); } q[++dfn_clock]=-u;out[u]=dfn_clock; } void update(int idx) { t[idx].sum=t[idx<<1].sum+t[idx<<1|1].sum; } void pushdown(int idx) { if(t[idx].lazy&&t[idx].l!=t[idx].r) { t[idx<<1].lazy+=t[idx].lazy; t[idx<<1|1].lazy+=t[idx].lazy; t[idx<<1].sum+=1LL*t[idx].lazy*t[idx<<1].num; t[idx<<1|1].sum+=1LL*t[idx].lazy*t[idx<<1|1].num; t[idx].lazy=0; } } void build(int idx,int l,int r) { t[idx].l=l,t[idx].r=r; if(l==r) { t[idx].lazy=0; if(q[l]>0){t[idx].sum=w[q[l]],t[idx].num=1;return;} else{t[idx].sum=-w[-q[l]],t[idx].num=-1;return;} } int mid=(l+r)>>1; build(idx<<1,l,mid),build(idx<<1|1,mid+1,r); t[idx].num=t[idx<<1].num+t[idx<<1|1].num; update(idx); } void add(int idx,int l,int r,int v) { if(l<=t[idx].l&&r>=t[idx].r) { t[idx].lazy+=v; t[idx].sum+=1LL*t[idx].num*v; return; } pushdown(idx); int mid=(t[idx].l+t[idx].r)>>1; if(r<=mid)add(idx<<1,l,r,v); else if(l>mid)add(idx<<1|1,l,r,v); else add(idx<<1,l,r,v),add(idx<<1|1,l,r,v); update(idx); } LL query(int idx,int l,int r) { if(l<=t[idx].l&&r>=t[idx].r)return t[idx].sum; pushdown(idx); int mid=(t[idx].l+t[idx].r)>>1; if(r<=mid)return query(idx<<1,l,r); else if(l>mid)return query(idx<<1|1,l,r); else return query(idx<<1,l,r)+query(idx<<1|1,l,r); } int main() { n=read(),m=read(); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++)w[i]=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); addedge(u,v); addedge(v,u); } dfs(1,0),build(1,1,dfn_clock); for(int i=1;i<=m;i++) { int opt=read(),x=read(),a; if(opt==1)a=read(),add(1,in[x],in[x],a),add(1,out[x],out[x],a); else if(opt==2)a=read(),add(1,in[x],out[x],a); else printf("%lld\n",query(1,1,in[x])); } return 0; }