Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
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
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
Sample Output
6
9
13
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
一道裸的树剖却因为建树时候的sb错误搞了半天
不想说什么(不过这个题好像会炸int)
#include<iostream> #include<cstdio> #include<cstring> #define LL long long #define MAXN (100000+50) using namespace std; LL Tree[MAXN]; LL T_num[MAXN]; LL Depth[MAXN]; LL Father[MAXN]; LL Sum[MAXN]; LL Son[MAXN]; LL Top[MAXN]; LL a[MAXN]; LL n,m,u,v,sum; LL head[MAXN],num_edge; struct node1 { LL val; LL add; } Segt[MAXN*4]; struct node2 { LL to; LL next; } edge[MAXN*2]; void add(LL u,LL v) { edge[++num_edge].to=v; edge[num_edge].next=head[u]; head[u]=num_edge; } void Dfs1(LL x) { Sum[x]=1; Depth[x]=Depth[Father[x]]+1; for (LL i=head[x]; i!=0; i=edge[i].next) if (edge[i].to!=Father[x]) { Father[edge[i].to]=x; Dfs1(edge[i].to); Sum[x]+=Sum[edge[i].to]; if (Son[x]==0 || (Sum[Son[x]]<Sum[edge[i].to])) Son[x]=edge[i].to; } } void Dfs2(LL x,LL tp) { T_num[x]=++sum; Tree[sum]=a[x]; Top[x]=tp; if (Son[x]) Dfs2(Son[x],tp); for (LL i=head[x]; i!=0; i=edge[i].next) if (edge[i].to!=Son[x] && edge[i].to!=Father[x]) Dfs2(edge[i].to,edge[i].to); } void Pushdown(LL node,LL l,LL r) { if (Segt[node].add!=0) { LL mid=(l+r)/2; Segt[node*2].val+=Segt[node].add*(mid-l+1); Segt[node*2+1].val+=Segt[node].add*(r-mid); Segt[node*2].add+=Segt[node].add; Segt[node*2+1].add+=Segt[node].add; Segt[node].add=0; } } void Build(LL node,LL l,LL r) { if (l==r) Segt[node].val=Tree[l]; else { LL mid=(l+r)/2; Build(node*2,l,mid); Build(node*2+1,mid+1,r); Segt[node].val=Segt[node*2].val+Segt[node*2+1].val; } } void Update(LL node,LL l,LL r,LL l1,LL r1,LL k) { if (l>r1 || r<l1) return; if (l1<=l && r<=r1) { Segt[node].val+=(r-l+1)*k; Segt[node].add+=k; return; } Pushdown(node,l,r); LL mid=(l+r)/2; Update(node*2,l,mid,l1,r1,k); Update(node*2+1,mid+1,r,l1,r1,k); Segt[node].val=Segt[node*2].val+Segt[node*2+1].val; } LL Query(LL node,LL l,LL r,LL l1,LL r1) { if (l>r1 || r<l1) return 0; if (l1<=l && r<=r1) return Segt[node].val; Pushdown(node,l,r); LL mid=(l+r)/2; return Query(node*2,l,mid,l1,r1)+Query(node*2+1,mid+1,r,l1,r1); } LL Get(LL x) { LL ans=0; while (x!=0) { ans+=Query(1,1,n,T_num[Top[x]],T_num[x]); x=Father[Top[x]]; } return ans; } int main() { scanf("%lld%lld",&n,&m); for (LL i=1; i<=n; ++i) scanf("%lld",&a[i]); for (LL i=1; i<=n-1; ++i) { scanf("%lld%lld",&u,&v); add(u,v); add(v,u); } Dfs1(1); Dfs2(1,1); Build(1,1,n); for (LL i=1; i<=m; ++i) { LL p,x,y; scanf("%lld",&p); if (p==1) { scanf("%lld%lld",&x,&y); Update(1,1,n,T_num[x],T_num[x],y); } if (p==2) { scanf("%lld%lld",&x,&y); Update(1,1,n,T_num[x],T_num[x]+Sum[x]-1,y); } if (p==3) { scanf("%lld",&x); printf("%lld\n",Get(x)); } } }