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));
}
}
}