这道题与模板之间,多了个确定哪个为根的操作;

这道题有技巧,并不需要真正去建立以某个节点为根的树

关于路径的操作,无论以哪个点为根,得出的答案无影响;

关于对子节点进行操作的,有几种情况,

当查询节点刚好是根节点的话,就直接从1开始遍历就好 (因为这道题是以1为根节点)

当查询的节点的孩子或孙子中包括根节点的话,则需要用根节点得出的值去剪掉这个根节点得出的值

(这里以查询作为例子,更新值也是同样的道理)

所以,整个代码中跟模板的区别是,多了一步 确定查询节点跟根节点关系的代码 (代码中的函数名为work2)

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #define Rint register int
  7. #define mem(a,b) memset(a,(b),sizeof(a))
  8. #define Temp template<typename T>
  9. using namespace std;
  10. typedef long long ll;
  11.  
  12. #define mid ((l+r)>>1)
  13. #define lson rt<<1,l,mid
  14. #define rson rt<<1|1,mid+1,r
  15. #define len (r-l+1)
  16. ll root,n; //n需要作为全局变量
  17. const ll maxn=+;
  18. //见题意
  19. ll e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
  20. //链式前向星数组,w[]、wt[]初始点权数组
  21. ll a[maxn<<],laz[maxn<<];
  22. //线段树数组、lazy操作
  23. ll son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
  24. //son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点
  25. ll res=;
  26. //查询答案
  27.  
  28. inline void add(ll x,ll y){//链式前向星加边
  29. to[++e]=y;
  30. nex[e]=beg[x];
  31. beg[x]=e;
  32. }
  33. //-------------------------------------- 以下为线段树
  34. inline void pushdown(ll rt,ll lenn){
  35. laz[rt<<]+=laz[rt];
  36. laz[rt<<|]+=laz[rt];
  37. a[rt<<]+=laz[rt]*(lenn-(lenn>>));
  38. a[rt<<|]+=laz[rt]*(lenn>>);
  39. // a[rt<<1]%=mod;
  40. // a[rt<<1|1]%=mod;
  41. laz[rt]=;
  42. }
  43.  
  44. inline void build(ll rt,ll l,ll r){
  45. if(l==r){
  46. a[rt]=wt[l];
  47. // if(a[rt]>mod)a[rt]%=mod;
  48. return;
  49. }
  50. build(lson);
  51. build(rson);
  52. a[rt]=a[rt<<]+a[rt<<|];
  53. }
  54.  
  55. inline void query(ll rt,ll l,ll r,ll L,ll R){
  56. if(L<=l&&r<=R){res+=a[rt];return;}
  57. else{
  58. if(laz[rt])pushdown(rt,len);
  59. if(L<=mid)query(lson,L,R);
  60. if(R>mid)query(rson,L,R);
  61. }
  62. }
  63.  
  64. inline void update(ll rt,ll l,ll r,ll L,ll R,ll k){
  65. if(L<=l&&r<=R){
  66. laz[rt]+=k;
  67. a[rt]+=k*len;
  68. }
  69. else{
  70. if(laz[rt])pushdown(rt,len);
  71. if(L<=mid)update(lson,L,R,k);
  72. if(R>mid)update(rson,L,R,k);
  73. a[rt]=a[rt<<]+a[rt<<|];
  74. }
  75. }
  76. //---------------------------------以上为线段树
  77. inline ll qRange(ll x,ll y){
  78. ll ans=;
  79. while(top[x]!=top[y]){//当两个点不在同一条链上
  80. if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
  81. res=;
  82. query(,,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
  83. ans+=res;
  84. // ans%=mod;//按题意取模
  85. x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
  86. }
  87. //直到两个点处于一条链上
  88. if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
  89. res=;
  90. query(,,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
  91. ans+=res;
  92. return ans;
  93. }
  94.  
  95. inline void updRange(ll x,ll y,ll k){//同上
  96. //k%=mod;
  97. while(top[x]!=top[y]){
  98. if(dep[top[x]]<dep[top[y]])swap(x,y);
  99. update(,,n,id[top[x]],id[x],k);
  100. x=fa[top[x]];
  101. }
  102. if(dep[x]>dep[y])swap(x,y);
  103. update(,,n,id[x],id[y],k);
  104. }
  105.  
  106. inline ll qSon(ll x){
  107. res=;
  108. query(,,n,id[x],id[x]+siz[x]-);//子树区间右端点为id[x]+siz[x]-1
  109. return res;
  110. }
  111.  
  112. inline void updSon(ll x,ll k){//同上
  113. update(,,n,id[x],id[x]+siz[x]-,k);
  114. }
  115.  
  116. inline void dfs1(ll x,ll f,ll deep){//x当前节点,f父亲,deep深度
  117. dep[x]=deep;//标记每个点的深度
  118. fa[x]=f;//标记每个点的父亲
  119. siz[x]=;//标记每个非叶子节点的子树大小
  120. ll maxson=-;//记录重儿子的儿子数
  121. for(ll i=beg[x];i;i=nex[i]){
  122. ll y=to[i];
  123. if(y==f)continue;//若为父亲则continue
  124. dfs1(y,x,deep+);//dfs其儿子
  125. siz[x]+=siz[y];//把它的儿子数加到它身上
  126. if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号
  127. }
  128. }
  129.  
  130. inline void dfs2(ll x,ll topf){//x当前节点,topf当前链的最顶端的节点
  131. id[x]=++cnt;//标记每个点的新编号
  132. wt[cnt]=w[x];//把每个点的初始值赋到新编号上来
  133. top[x]=topf;//这个点所在链的顶端
  134. if(!son[x])return;//如果没有儿子则返回
  135. dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理
  136. for(ll i=beg[x];i;i=nex[i]){
  137. ll y=to[i];
  138. if(y==fa[x]||y==son[x])continue;
  139. dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链
  140. }
  141. }
  142. ll check2(ll xx,ll yy){
  143. ll rt=xx,lst=yy;
  144. while(top[xx]!=top[yy]){
  145. if(dep[top[xx]]<dep[top[yy]]) swap(xx,yy);
  146. lst=top[xx];xx=fa[top[xx]];
  147. }
  148. if(dep[xx]>dep[yy]) swap(xx,yy);
  149. if(xx!=rt) return ; //如果得出的点不是等于查询节点
  150. //则说明没有关系,这里举个例子,比如在一个树中,他的父亲节点是根节点,
  151. //那么就没有关系;换一个说法(如果yy不是xx的子树,则没有影响)
  152. //两个节点没有关系,return 0
  153. if(fa[lst]==xx) return lst; //如果lst的父亲是这个查询节点,则根节点
  154. //便是这个lst;
  155. return son[xx]; //可以说return son[xx]是最难理解的了。
  156. } //不过还是理解了,开心! 如果fa[lst]的节点是查询节点的子节点或者孙节点;
  157. //那么从他重儿子以下的点都是不在查询范围(更新范围)的,这里画图模拟一遍
  158. //就会发现就是这么个道理。
  159. int main()
  160. {
  161. scanf("%lld",&n);
  162. for(ll i=;i<=n;i++) scanf("%lld",&w[i]);
  163. for(ll i=;i<=n;i++){
  164. ll t;
  165. scanf("%lld",&t);
  166. add(t,i);add(i,t);
  167. }
  168. ll m;
  169. scanf("%lld",&m);
  170. dfs1(,,);
  171. dfs2(,);
  172. build(,,n);
  173. root=;
  174. while(m--){
  175. ll k,x,y,z;
  176. scanf("%lld",&k);
  177. if(k==){
  178. scanf("%lld",&root);
  179. }
  180. if(k==){
  181. scanf("%lld%lld%lld",&x,&y,&z);
  182. updRange(x,y,z);
  183. }
  184. if(k==){
  185. scanf("%lld%lld",&x,&z);
  186. if(x==root) {updSon(,z);continue;}
  187. y=check2(x,root);
  188. if(y==) updSon(x,z);
  189. else{
  190. updSon(,z);
  191. updSon(y,-z);
  192. }
  193. }
  194. if(k==){
  195. scanf("%lld%lld",&x,&y);
  196. printf("%lld\n",qRange(x,y));
  197. }
  198. if(k==){
  199. scanf("%lld",&x);
  200. if(x==root){
  201. printf("%lld\n",qSon());
  202. continue;
  203. }
  204. y=check2(x,root);
  205. if(y==) printf("%lld\n",qSon(x));
  206. else{
  207. printf("%lld\n",qSon()-qSon(y));
  208. }
  209. }
  210. }
  211. return ;
  212. }

树链剖分 (ZQU1607)的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  2. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  3. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  4. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  5. 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)

    题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...

  6. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  7. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  8. bzoj3631树链剖分

    虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...

  9. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  10. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

随机推荐

  1. ZDialog关闭父窗口、往父窗口传值、刷新父窗口

    关闭自己 //关闭自己 top.Dialog.close(); 关闭父窗口 //关闭父窗口 parentDialog.parentWindow.close() 往父窗口传值 //在本页面,调用父页面方 ...

  2. 题解【AcWing883】高斯消元解线性方程组

    题面 高斯消元模板题. 这里直接讲述一下高斯消元的算法流程: 枚举每一列 \(c\): 找到第 \(c\) 列绝对值最大的一行: 将这一行换到最上面: 将该行的第一个数变成 \(1\): 将下面所有行 ...

  3. springboot 扫描不到包 @SpringBootApplication 自动配置原理

    解决方案 在main类中增加注解 @ComponentScan("com.test.test.*") 扫描具体的包 @ComponentScan(basePackages = {& ...

  4. [转]JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释

    jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分: ...

  5. 占位 LR

    占位 LR include: LR403

  6. <if test="type == '0' ">没有进去这个判断的问题

    在MyBatis的mapp文件中的if判断中是这样写的 <if test="type == '0' "> and so1.id = #{unitcode} </i ...

  7. 颜色color转为rgb格式

    function convertHexToRGB(color) {       if (color.length === 4) {             let extendedColor = &q ...

  8. C++-POJ2975-Nim

    题目把Nim游戏为什么可以取异或和讲解得十分清楚,建议多读几次,理解一下 再一个,可以把每次异或视为一次取数,因此(k[i]^sg)<k[i]即为一种可行操作 /* Nim is a 2-pla ...

  9. x = cos x 的解析形式

    x = cos x 的解析形式 玩计算器的发现 大家都玩过计算器吧, 不知注意到没有. 输入任意数, 然后不断按最后总会输出. 什么, 你说明明记得是:? 哦, 因为你用了角度制. 这一系列操作等价于 ...

  10. windows10中docker nginx开启 但页面访问不了

    Windows下对docker端口进行映射,但是当你在主机的浏览器中,打开localhost:port无法访问对应的服务. docker是运行在Linux上的,在Windows中运行docker,实际 ...