#139. 树链剖分

题目描述

这是一道模板题。

给定一棵 $n$个节点的树,初始时该树的根为 111 号节点,每个节点有一个给定的权值。下面依次进行 $m$ 个操作,操作分为如下五种类型:

  • 换根:将一个指定的节点设置为树的新根。

  • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。

  • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。

  • 询问路径:询问某条路径上节点的权值和。

  • 询问子树:询问某个子树内节点的权值和

输入格式

第一行为一个整数 n,表示节点的个数。

第二行 n 个整数表示第 iii 个节点的初始权值 $a_i$​。

第三行 n−1 个整数,表示 i+1i+1i+1 号节点的父节点编号$ fi+1 (1⩽fi+1⩽n)f_{i+1}\ (1 \leqslant f_{i+1} \leqslant n)fi+1​ (1⩽fi+1​⩽n)。$

第四行一个整数 m,表示操作个数。

接下来 m 行,每行第一个整数表示操作类型编号:$(1⩽u,v⩽n)(1 \leqslant u, v \leqslant n)(1⩽u,v⩽n)$

  • 若类型为 111,则接下来一个整数 u,表示新根的编号。

  • 若类型为 222,则接下来三个整数 u,v,ku,v,ku,v,k,分别表示路径两端的节点编号以及增加的权值。

  • 若类型为 333,则接下来两个整数 u,ku,ku,k,分别表示子树根节点编号以及增加的权值。

  • 若类型为 444,则接下来两个整数 u,vu,vu,v,表示路径两端的节点编号。

  • 若类型为 555,则接下来一个整数 u,表示子树根节点编号。

输出格式

对于每一个类型为 444 或 555 的操作,输出一行一个整数表示答案。

样例
样例输入
  1. 6
  2. 1 2 3 4 5 6
  3. 1 2 1 4 4
  4. 6
  5. 4 5 6
  6. 2 2 4 1
  7. 5 1
  8. 1 4
  9. 3 1 2
  10. 4 2 5
样例输出
  1. 15
  2. 24
  3. 19
数据范围与提示

对于 $100%100\%100%$ 的数据,$1⩽n,m,k,ai⩽1051\leqslant n,m,k,a_i\leqslant 10^51⩽n,m,k,ai​⩽105$。数据有一定梯度。

题意:树链加,子树加,需要支持换根,查询树链和,子树和

题解:

树链剖分模板,树链加和查询直接树链剖分即可,

注意到树链剖分有个很方便的性质就是链剖的序列其实也是dfs序,记录一个点的序列上起点和终点就可以顺便维护子树,

换根的话分类讨论一下,一直以1号点为根,对树链的修查无影响,考虑子树:

假设访问u号点,在以1号点为根的形态下:

当前根rt,如果u==rt则u的子树为整个以1为根的树,

如果rt是u的子树里的节点,那么u所代表的的子树就是整个子树 - rt的祖先里u的儿子的  子树 ,

如果rt不是u的子树里的节点,那么u的子树就是以1为根时u的子树;

这样操作后也是区间,可以和前两个一起维护;

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<queue>
  6. #include<cmath>
  7. #include<vector>
  8. #include<stack>
  9. #include<map>
  10. #define ls (k<<1)
  11. #define rs (k<<1|1)
  12. #define Run(i,l,r) for(int i=l;i<=r;i++)
  13. #define Don(i,l,r) for(int i=l;i>=r;i--)
  14. #define ll long long
  15. #define inf 0x3f3f3f3f
  16. using namespace std;
  17. const int N=;
  18. int n,m,o,hd[N],tp[N],st[N],ed[N],idx,son[N],fa[N],w[N],sz[N],dep[N],root;//
  19. ll val[N],sum[N<<],ly[N<<];//
  20. struct Edge{int v,nt;}E[N<<]; //
  21. char gc(){
  22. static char*p1,*p2,s[];
  23. if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
  24. return(p1==p2)?EOF:*p1++;
  25. }//
  26. int rd(){
  27. int x=,f=; char c=gc();
  28. while(c<''||c>''){if(c=='-')f=-;c=gc();}
  29. while(c>=''&&c<=''){x=(x<<)+(x<<)+c-'',c=gc();}
  30. return x*f;
  31. }//
  32. void adde(int u,int v){
  33. E[o]=(Edge){v,hd[u]};hd[u]=o++;
  34. E[o]=(Edge){u,hd[v]};hd[v]=o++;
  35. }//
  36. void dfsA(int u,int F){
  37. dep[u]=dep[F]+;
  38. son[u]=; sz[u]=;
  39. for(int i=hd[u];~i;i=E[i].nt){
  40. int v=E[i].v;
  41. if(v==F)continue;
  42. dfsA(v,u);
  43. sz[u]+=sz[v];
  44. if(sz[v]>sz[son[u]])son[u]=v;
  45. }
  46. }//
  47. void dfsB(int u,int T){
  48. tp[u]=T; val[st[u]=++idx]=w[u];
  49. if(son[u])dfsB(son[u],T);
  50. for(int i=hd[u];~i;i=E[i].nt){
  51. int v=E[i].v;
  52. if(v==son[u]||v==fa[u])continue;
  53. dfsB(v,v);
  54. }
  55. ed[u]=idx;
  56. }//
  57. void pushup(int k){sum[k]=sum[ls]+sum[rs];}//
  58. void mfy(int k,int l,int r,ll v){sum[k]+=v*(r-l+);ly[k]+=v;}//
  59. void pushdown(int k,int l,int r){
  60. if(ly[k]){
  61. int mid=(l+r)>>;
  62. mfy(ls,l,mid,ly[k]);
  63. mfy(rs,mid+,r,ly[k]);
  64. ly[k]=;
  65. }
  66. }//
  67. void build(int k,int l,int r){
  68. if(l==r){sum[k]=val[l];ly[k]=;return;}
  69. int mid=(l+r)>>;
  70. build(ls,l,mid);
  71. build(rs,mid+,r);
  72. pushup(k);
  73. }//
  74. void update(int k,int l,int r,int x,int y,ll v){
  75. if(l==x&&r==y)mfy(k,l,r,v);
  76. else {
  77. pushdown(k,l,r);
  78. int mid=(l+r)>>;
  79. if(y<=mid)update(ls,l,mid,x,y,v);
  80. else if(x>mid)update(rs,mid+,r,x,y,v);
  81. else update(ls,l,mid,x,mid,v) , update(rs,mid+,r,mid+,y,v);
  82. pushup(k);
  83. }
  84. }//
  85. ll query(int k,int l,int r,int x,int y){
  86. if(l==x&&r==y)return sum[k];
  87. else {
  88. pushdown(k,l,r);
  89. int mid=(l+r)>>;
  90. if(y<=mid)return query(ls,l,mid,x,y);
  91. else if(x>mid)return query(rs,mid+,r,x,y);
  92. else return query(ls,l,mid,x,mid) + query(rs,mid+,r,mid+,y);
  93. }
  94. }//
  95. int child(int u,int v){
  96. while(tp[u]!=tp[v]){
  97. u=tp[u];
  98. if(fa[u]==v)return u;
  99. u=fa[u];
  100. }
  101. return son[v];
  102. }//
  103. void update1(int u,int v,int x){
  104. while(tp[u]!=tp[v]){
  105. if(dep[tp[u]]<dep[tp[v]])swap(u,v);
  106. update(,,n,st[tp[u]],st[u],x);
  107. u=fa[tp[u]];
  108. }
  109. if(dep[u]<dep[v])swap(u,v);
  110. update(,,n,st[v],st[u],x);
  111. }//
  112. void update2(int u,int x){
  113. if(u==root){update(,,n,,n,x);}
  114. else if(st[u]<=st[root]&&ed[root]<=ed[u]){
  115. int t = child(root,u);
  116. update(,,n,,n,x);
  117. update(,,n,st[t],ed[t],-x);
  118. }
  119. else{update(,,n,st[u],ed[u],x);}
  120. }//
  121. void query1(int u,int v){
  122. ll ret=;
  123. while(tp[u]!=tp[v]){
  124. if(dep[tp[u]]<dep[tp[v]])swap(u,v);
  125. ret += query(,,n,st[tp[u]],st[u]);
  126. u=fa[tp[u]];
  127. }
  128. if(dep[u]<dep[v])swap(u,v);
  129. ret += query(,,n,st[v],st[u]);
  130. printf("%lld\n",ret);
  131. }//
  132. void query2(int u){
  133. ll ret=;
  134. if(u==root)ret=query(,,n,,n);
  135. else if(st[u]<=st[root]&&ed[root]<=ed[u]){
  136. int t = child(root,u);
  137. ret += query(,,n,,n);
  138. ret -= query(,,n,st[t],ed[t]);
  139. }
  140. else{ret = query(,,n,st[u],ed[u]);}
  141. printf("%lld\n",ret);
  142. }//
  143. int main(){
  144. //freopen("loj139.in","r",stdin);
  145. //freopen("loj139.out","w",stdout);
  146. n=rd();
  147. for(int i=;i<=n;i++)w[i]=rd(),hd[i]=-;
  148. for(int i=;i<=n;i++)adde(fa[i]=rd(),i);
  149. dfsA(root=,);dfsB(,);
  150. build(,,n);
  151. m=rd();
  152. for(int i=,u,v,x;i<=m;i++){
  153. int op=rd();
  154. if(op==)root=rd();
  155. else if(op==){u=rd();v=rd();x=rd();update1(u,v,x);}
  156. else if(op==){u=rd();x=rd();update2(u,x);}
  157. else if(op==){u=rd();v=rd();query1(u,v);}
  158. else {u=rd();query2(u);}
  159. }
  160. return ;
  161. }//by tkys_Austin;

【loj#139】树链剖分的更多相关文章

  1. LOJ#139. 树链剖分

    LOJ#139. 树链剖分 题目描述 这是一道模板题. 给定一棵$n$个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个 ...

  2. LibreOJ #139 树链剖分 [树链剖分,线段树]

    题目传送门 树链剖分 题目描述 这是一道模板题. 给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个指定的 ...

  3. BZOJ 2157: 旅游( 树链剖分 )

    树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...

  4. LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】

    题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...

  5. NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分

    原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...

  6. 树链剖分(附带LCA和换根)——基于dfs序的树上优化

    .... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...

  7. BZOJ_2243 [SDOI2011]染色 【树链剖分+线段树】

    一 题目 [SDOI2011]染色 二 分析 感觉树链剖分的这些题真的蛮考验码力的,自己的码力还是不够啊!o(╯□╰)o 还是比较常规的树链剖分,但是一定记得这里的线段树在查询的时候一定要考虑链于链相 ...

  8. BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】

    一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...

  9. SPOJ QTree【树链剖分】

    一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...

随机推荐

  1. 学习笔记之glog的使用

    下载源码,使用cmake编译,最后得到了32位的静态库 glog.lib 使用库时要注意添加以下预定义: GLOG_NO_ABBREVIATED_SEVERITIES; GOOGLE_GLOG_DLL ...

  2. Jenkins Tomcat安装设置

    Jenkins Tomcat安装设置 以下为必须满足Jenkins Tomcat设置的先决条件. 第1步:验证安装Java 要验证Java安装,打开控制台并执行以下Java命令. OS 任务 命令 W ...

  3. HBASE理论篇

    1.Hbase是什么 HBase是一种构建在HDFS之上的分布式.面向列的存储系统.在需要实时读写.随机访问超大规模数据集时,可以使用HBase. 尽管已经有许多数据存储和访问的策略和实现方法,但事实 ...

  4. Nginx特性验证-反向代理/负载均衡/页面缓存/URL重定向

    原文发表于cu:2016-08-25 参考文档: Nginx 反向代理.负载均衡.页面缓存.URL重写等:http://freeloda.blog.51cto.com/2033581/1288553 ...

  5. Chrome 鲜为人知的秘籍(内部协议)&&Chrome功能指令大全

    楼主以 Chrome 版本 39.0.2171.95 m 为例,耗费2小时的记录: chrome://accessibility 用于查看浏览器当前访问的标签,打开全局访问模式可以查看:各个标签页面的 ...

  6. BFC的表象认识

    首先字面翻译,这三个字母分别代表什么,box,formatting, context,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用. 形象点就是说一种规范,规范什么呢?规范盒子内部 ...

  7. Alpha 冲刺(9/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ...

  8. Eclipse的黑色主题背景(github)

    MoonRise UI Theme   An early version of a dark UI theme for Eclipse 4+. Requirements Eclipse 4.2+ In ...

  9. css3 关于文字,字体属性(转载)

    1.text-overflow属性(实现省略号效果) text-overflow用来设置是否使用一个省略标记(…)标示对象内文本的溢出. [语法] ❤text-overflow只是用来说明文字溢出时用 ...

  10. String、StringBuilder与StringBuffer的区别

    1.String类是public.final修饰的. 在Java中,被final修饰的类是不允许被继承的,并且String它的成员方法都默认为final方法. 查看源码得知,String类其实是通过c ...