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

Sample Output

6
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*];
struct node2
{
LL to;
LL next;
} edge[MAXN*];
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]=;
Depth[x]=Depth[Father[x]]+;
for (LL i=head[x]; i!=; 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]== || (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!=; 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!=)
{
LL mid=(l+r)/;
Segt[node*].val+=Segt[node].add*(mid-l+);
Segt[node*+].val+=Segt[node].add*(r-mid);
Segt[node*].add+=Segt[node].add;
Segt[node*+].add+=Segt[node].add;
Segt[node].add=;
}
} void Build(LL node,LL l,LL r)
{
if (l==r)
Segt[node].val=Tree[l];
else
{
LL mid=(l+r)/;
Build(node*,l,mid);
Build(node*+,mid+,r);
Segt[node].val=Segt[node*].val+Segt[node*+].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+)*k;
Segt[node].add+=k;
return;
}
Pushdown(node,l,r);
LL mid=(l+r)/;
Update(node*,l,mid,l1,r1,k);
Update(node*+,mid+,r,l1,r1,k);
Segt[node].val=Segt[node*].val+Segt[node*+].val;
} LL Query(LL node,LL l,LL r,LL l1,LL r1)
{
if (l>r1 || r<l1)
return ;
if (l1<=l && r<=r1)
return Segt[node].val;
Pushdown(node,l,r);
LL mid=(l+r)/;
return Query(node*,l,mid,l1,r1)+Query(node*+,mid+,r,l1,r1);
} LL Get(LL x)
{
LL ans=;
while (x!=)
{
ans+=Query(,,n,T_num[Top[x]],T_num[x]);
x=Father[Top[x]];
}
return ans;
} int main()
{
scanf("%lld%lld",&n,&m);
for (LL i=; i<=n; ++i)
scanf("%lld",&a[i]);
for (LL i=; i<=n-; ++i)
{
scanf("%lld%lld",&u,&v);
add(u,v);
add(v,u);
}
Dfs1();
Dfs2(,);
Build(,,n);
for (LL i=; i<=m; ++i)
{
LL p,x,y;
scanf("%lld",&p);
if (p==)
{
scanf("%lld%lld",&x,&y);
Update(,,n,T_num[x],T_num[x],y);
}
if (p==)
{
scanf("%lld%lld",&x,&y);
Update(,,n,T_num[x],T_num[x]+Sum[x]-,y);
}
if (p==)
{
scanf("%lld",&x);
printf("%lld\n",Get(x));
}
}
}

最新文章

  1. Javascript到PHP加密通讯的简单实现
  2. console.log 被重写覆盖以后如何恢复
  3. CSS HTML链接去掉小手与增添小手
  4. Python3缩进对逻辑的影响
  5. IE6常见bug整理
  6. C:冒泡排序
  7. Ext.QuickTips.init();
  8. 转:窗口启用/禁用功能函数EnableWindow的使用
  9. java 线程池的用法
  10. 修改redis端口号
  11. Redis多服务器负载均衡的实现
  12. WPF:在DataTemplate中使用DataType
  13. hdu 2126 Buy the souvenirs 【输出方案数】【01背包】(经典)
  14. MySQL死锁问题分析及解决方法实例详解(转)
  15. spring ContentNegotiationManagerFactoryBean 内容协商
  16. mybatis mapper接口开发dao层
  17. 20165210 Java第四周学习总结
  18. cb6xe7代码提示风格变化
  19. 做题记录 To 2019.2.13
  20. background image

热门文章

  1. The request sent by the client was syntactically incorrect.
  2. Java中获取32位UUID
  3. package.json参数简单介绍
  4. 第二十六天- C/S架构 通信流程 socket
  5. vs中发布WebSever时启用HTTP-POST和HTTP-GET这两种协议
  6. 使用Python生成基础验证码教程
  7. THUSC2017 游记
  8. JavaScript对象遍历属性和值
  9. Add map surrounds using the SymbologyControl
  10. vip会员统计表 (vip等级是灵活配置的 非写死1是金卡用户 2是什么 等)