LOJ2125 树上操作

题目描述

有一棵点数为 N 的树,以点 1 为根,且树有点权。然后有 M 个操作,分为三种:

  1. 把某个节点 x 的点权增加 aa 。
  2. 把某个节点 x 为根的子树中所有点的点权都增加 a 。
  3. 询问某个节点 x 到根的路径中所有点的点权和。

输入格式

第一行包含两个整数 N, M。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 fr,to , 表示该树中存在一条边(fr,to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类(1-3) ,之后接这个操作的参数(x 或者 x a) 。

输出格式

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

样例

样例输入

  1. 5 5
  2. 1 2 3 4 5
  3. 1 2
  4. 1 4
  5. 2 3
  6. 2 5
  7. 3 3
  8. 1 2 1
  9. 3 5
  10. 2 1 2
  11. 3 3

样例输出

  1. 6
  2. 9
  3. 13

数据范围与提示

对于 100% 的数据, N,M≤10^5 ,且所有输入数据的绝对值都不会超过 10^6 。

________________________________________________________________________________________

简单的树链剖分,而且树上的查询也比较简单,只是从某个节点到根的权值和。需要注意的如何处理子树的权值修改。这个就是用到了DFS序。需要记录每个点为跟的子树在线段树中左右边界。

________________________________________________________________________________________

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 typedef long long ll;
  4. 4 const ll maxn=1e5+10;
  5. 5 ll n,m;
  6. 6 ll w[maxn];
  7. 7 struct edge
  8. 8 {
  9. 9 int u,v,nxt;
  10. 10 }e[maxn<<1];
  11. 11 ll head[maxn],js;
  12. 12 void addage(ll u,ll v)
  13. 13 {
  14. 14 e[++js].u=u;e[js].v=v;
  15. 15 e[js].nxt=head[u];head[u]=js;
  16. 16 }
  17. 17 ll dep[maxn],siz[maxn],fat[maxn],son[maxn];
  18. 18 void dfs(int u,int fa)
  19. 19 {
  20. 20 siz[u]=1;
  21. 21 dep[u]=dep[fa]+1;
  22. 22 fat[u]=fa;
  23. 23 for(ll i=head[u];i;i=e[i].nxt)
  24. 24 {
  25. 25 ll v=e[i].v;
  26. 26 if(v==fa)continue;
  27. 27 dfs(v,u);
  28. 28 siz[u]+=siz[v];
  29. 29 if(!son[u] || siz[son[u]]<siz[v])son[u]=v;
  30. 30 }
  31. 31 }
  32. 32 ll lp[maxn],rp[maxn],top[maxn],fos[maxn],p;
  33. 33 void getpos(ll u,ll fa)
  34. 34 {
  35. 35 lp[u]=++p;
  36. 36 fos[p]=u;
  37. 37 top[u]=fa;
  38. 38 if(!son[u])
  39. 39 {
  40. 40 rp[u]=p;
  41. 41 return;
  42. 42 }
  43. 43 getpos(son[u],fa);
  44. 44 for(ll i=head[u];i;i=e[i].nxt)
  45. 45 {
  46. 46 ll v=e[i].v;
  47. 47 if(v!=fat[u] && v!=son[u])getpos(v,v);
  48. 48 }
  49. 49 rp[u]=p;
  50. 50 }
  51. 51 ll sum[maxn<<2],delt[maxn<<2];
  52. 52 inline void updat(ll cur)
  53. 53 {
  54. 54 sum[cur]=sum[cur<<1]+sum[cur<<1|1];
  55. 55 }
  56. 56 void build(ll cur,ll l,ll r)
  57. 57 {
  58. 58 if(l==r)
  59. 59 {
  60. 60 sum[cur]=w[fos[l]];
  61. 61 return;
  62. 62 }
  63. 63 ll mid=(l+r)>>1;
  64. 64 build(cur<<1,l,mid);
  65. 65 build(cur<<1|1,mid+1,r);
  66. 66 updat(cur);
  67. 67 }
  68. 68 void down(ll cur,ll l,ll r)
  69. 69 {
  70. 70 ll mid=(l+r)>>1;
  71. 71 delt[cur<<1]+=delt[cur];
  72. 72 delt[cur<<1|1]+=delt[cur];
  73. 73 sum[cur<<1]+=delt[cur]*(mid-l+1);
  74. 74 sum[cur<<1|1]+=delt[cur]*(r-mid);
  75. 75 delt[cur]=0;
  76. 76 }
  77. 77 void add(ll cur,ll l,ll r,ll p,ll x)
  78. 78 {
  79. 79 if(l==r)
  80. 80 {
  81. 81 sum[cur]+=x;
  82. 82 return ;
  83. 83 }
  84. 84 ll mid=(l+r)>>1;
  85. 85 if(delt[cur])down(cur,l,r);
  86. 86 if(p<=mid)add(cur<<1,l,mid,p,x);
  87. 87 else add(cur<<1|1,mid+1,r,p,x);
  88. 88 updat(cur);
  89. 89 }
  90. 90 void add_(ll cur,ll l,ll r,ll ql,ll qr,ll x)
  91. 91 {
  92. 92 if(ql<=l && r<=qr)
  93. 93 {
  94. 94 sum[cur]+=(r-l+1)*x;
  95. 95 delt[cur]+=x;
  96. 96 return ;
  97. 97 }
  98. 98 down(cur,l,r);
  99. 99 ll mid=(l+r)>>1;
  100. 100 if(ql<=mid)add_(cur<<1,l,mid,ql,qr,x);
  101. 101 if(mid<qr)add_(cur<<1|1,mid+1,r,ql,qr,x);
  102. 102 updat(cur);
  103. 103 }
  104. 104 ll query(ll cur,ll l,ll r,ll ql,ll qr)
  105. 105 {
  106. 106 if(ql<=l && r<=qr)return sum[cur];
  107. 107 ll ans=0,mid=(l+r)>>1;
  108. 108 if(delt[cur])down(cur,l,r);
  109. 109 if(ql<=mid)ans+=query(cur<<1,l,mid,ql,qr);
  110. 110 if(mid<qr)ans+=query(cur<<1|1,mid+1,r,ql,qr);
  111. 111 return ans;
  112. 112 }
  113. 113 ll ask(ll x)
  114. 114 {
  115. 115 ll ans=0;
  116. 116 while(x)
  117. 117 {
  118. 118 ll tpx=top[x];
  119. 119 ans+=query(1,1,n,lp[tpx],lp[x]);
  120. 120 x=fat[tpx];tpx=top[x];
  121. 121 }
  122. 122 return ans;
  123. 123 }
  124. 124 int main()
  125. 125 {
  126. 126 scanf("%lld%lld",&n,&m);
  127. 127 for(int i=1;i<=n;++i)scanf("%lld",w+i);
  128. 128 for(ll u,v,i=1;i<n;++i)
  129. 129 {
  130. 130 scanf("%lld%lld",&u,&v);
  131. 131 addage(u,v);addage(v,u);
  132. 132 }
  133. 133 dfs(1,0);
  134. 134 getpos(1,1);
  135. 135 build(1,1,n);
  136. 136 while(m--)
  137. 137 {
  138. 138 ll x,a,op;
  139. 139 scanf("%lld%lld",&op,&x);
  140. 140 if(op!=3)scanf("%lld",&a);
  141. 141 if(op==1)add(1,1,n,lp[x],a);
  142. 142 else if(op==2)add_(1,1,n,lp[x],rp[x],a);
  143. 143 else printf("%lld\n",ask(x));
  144. 144 }
  145. 145 return 0;
  146. 146 }

LOJ2125的更多相关文章

随机推荐

  1. java中自定义一个异常类 在某些情况抛出自定的异常 ----------阻断程序

    //=============定义异常类 package org.springblade.flow.engine.errorException; /** * 自定义异常处理写入sap失败 */ pub ...

  2. ArrayList的删除姿势你都知道了吗

    引言 前几天有个读者由于看了<ArrayList哪种遍历效率最好,你真的弄明白了吗?>问了个问题普通for循环ArrayList为什么不能删除连续重复的两个元素?其实这个描述是不正确的.正 ...

  3. C#设计模式——建造者模式(Builder Pattern)

    1.建造者模式简介 1.1>.定义 建造者模式(Builder)将复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 1.2>.使用频率  中低 1.3>.原型模式应用 ...

  4. UDP 通讯方式

    1.创建套接字:2.绑定端口:3.收发数据: 收到的数据中包含发送方的端口信息4.关闭套接字:

  5. uniapp H5引入腾讯地图

    在网上搜索了许多关于uniapp引入腾讯地图的方法都以失败告终,我开发的应用主要使用于H5,小程序与H5是不同的sdk,就不在这说了,况且小程序有手把手教学,可参考腾讯地图官网https://lbs. ...

  6. C#自定义控件的应用(数据绑定,属性等)

    刚刚开始程序设计的码农生涯,也许一些开发工具上的控件可以满足我们的需求,但是随之时间的迁移,我们对控件的呈现形式需求越来越多样化,这个时候就需要我们来自定义控件,我是一个刚刚入职没多久的菜鸟,接触软件 ...

  7. DB2在渗透中的应用(转载)

    原文地址:http://drops.wooyun.org/tips/16673 0x00 DB2简介 DB2是IBM公司推出关系型数据库管理系统. 现今DB2主要包含以下三个系列: DB2 for L ...

  8. 使用sublime text3搭建Python编辑环境

    最近在工作遇到一个难题. 我所在的测试组有一套PC软件前端自动化工程,在进行自动化测试时,需要在一台古老的xp机器上运行,但这台古老的xp机器带给我诸多烦恼,特别是使用Pycharm编辑器时,我遇到了 ...

  9. three.js canvas内场景生成图片 canvas生成图片

    第一种最简单的方法: 1 threeBox.render();//重点 解决拿到图片后为黑色 2 3 let src=threeBox.renderer.domElement.toDataURL(); ...

  10. 【Flutter】可滚动组件简介

    前言 当组件内容超过当前显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误.为此,Flutter提供了多种可滚动组件(Scrollable Widget)用于 ...