<更新提示>

<第一次更新>


<正文>

LCA

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根 的距离+1。

设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。 (即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

Input Format

第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。

Output Format

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

Sample Input

  1. 5 2
  2. 0
  3. 0
  4. 1
  5. 1
  6. 1 4 3
  7. 1 4 2

Sample Output

  1. 8
  2. 5

解析

容易发现一个询问可以拆成两个询问:

\[\sum_{i=l}^rdep[LCA(i,z)]=\sum_{i=1}^rdep[LCA(i,z)]-\sum_{i=1}^{l-1}dep[LCA(i,z)]
\]

都是前缀和形式的,方便我们处理。

对于一个前缀和询问,我们可以发现它的贡献具有一个实际意义:也就是求每一个\(i\)与\(z\)公共祖先的个数。进一步,我们可以这样理解:把每一个节点\(i\)到根的路径上的点点权都加一,求\(z\)到更路径上的点权和。

我们都知道直接树上加链和查询链可以用树链剖分,但是各个询问之间好像相互有影响。

最简单的解决方法就是把询问离线。我们之前已经把询问转化为前缀和的形式了,那就把所有询问按照\(r\)排序,这样依次处理询问就没有影响了。

\(Code:\)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 50020 , Mod = 201314;
  4. struct node { int l,r,tag; long long cnt; };
  5. struct SegmentTree
  6. {
  7. node ver[N<<2];
  8. #define l(p) ver[p].l
  9. #define r(p) ver[p].r
  10. #define cnt(p) ver[p].cnt
  11. #define tag(p) ver[p].tag
  12. inline void build(int p,int l,int r)
  13. {
  14. l(p) = l , r(p) = r , cnt(p) = tag(p) = 0;
  15. if ( l == r ) return;
  16. int mid = l + r >> 1;
  17. build( p<<1 , l , mid );
  18. build( p<<1|1 , mid+1 , r );
  19. }
  20. inline void update(int p) { cnt(p) = cnt(p<<1) + cnt(p<<1|1); }
  21. inline void spread(int p)
  22. {
  23. if ( tag(p) )
  24. {
  25. tag(p<<1) = ( tag(p<<1) + tag(p) ) % Mod;
  26. tag(p<<1|1) = ( tag(p<<1|1) + tag(p) ) % Mod;
  27. cnt(p<<1) = ( cnt(p<<1) + 1LL * ( r(p<<1) - l(p<<1) + 1 ) * tag(p) % Mod ) % Mod;
  28. cnt(p<<1|1) = ( cnt(p<<1|1) + 1LL * ( r(p<<1|1) - l(p<<1|1) + 1 ) * tag(p) % Mod ) % Mod;
  29. tag(p) = 0;
  30. }
  31. }
  32. inline void modify(int p,int l,int r,int v)
  33. {
  34. if ( l <= l(p) && r >= r(p) )
  35. {
  36. cnt(p) = ( cnt(p) + ( r(p) - l(p) + 1 ) * v % Mod ) % Mod;
  37. tag(p) = ( tag(p) + v ) % Mod; return;
  38. }
  39. spread( p );
  40. int mid = l(p) + r(p) >> 1;
  41. if ( l <= mid ) modify( p<<1 , l , r , v );
  42. if ( r > mid ) modify( p<<1|1 , l , r , v );
  43. update( p );
  44. }
  45. inline int query(int p,int l,int r)
  46. {
  47. if ( l <= l(p) && r >= r(p) ) return cnt(p);
  48. spread( p );
  49. int mid = l(p) + r(p) >> 1 , res = 0;
  50. if ( l <= mid ) res = ( res + query( p<<1 , l , r ) ) % Mod;
  51. if ( r > mid ) res = ( res + query( p<<1|1 , l , r ) ) % Mod;
  52. return res;
  53. }
  54. };
  55. SegmentTree Tree;
  56. struct edge { int ver,next; } e[N*2];
  57. struct query { int r,z,id,f; } a[N*2];
  58. int n,m,t,Head[N],tot;
  59. int fa[N],dep[N],son[N],size[N],top[N],id[N],cnt;
  60. long long ans[N];
  61. inline void insert(int x,int y)
  62. {
  63. e[++t] = (edge){y,Head[x]} , Head[x] = t;
  64. e[++t] = (edge){x,Head[y]} , Head[y] = t;
  65. }
  66. inline int read(void)
  67. {
  68. int x = 0 , w = 0; char ch = ' ';
  69. while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
  70. while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
  71. return w ? -x : x;
  72. }
  73. inline void input(void)
  74. {
  75. n = read() , m = read();
  76. for ( int i = 2 ; i <= n ; i++ )
  77. insert( i , read() + 1 );
  78. for ( int i = 1 ; i <= m ; i++ )
  79. {
  80. int l = read() + 1 , r = read() + 1 , z = read() + 1;
  81. a[++tot] = (query){ r , z , i , 1 };
  82. a[++tot] = (query){ l-1 , z , i , -1 };
  83. }
  84. }
  85. inline void dfs1(int x,int f,int depth)
  86. {
  87. fa[x] = f , dep[x] = depth , size[x] = 1;
  88. int Max = -1;
  89. for ( int i = Head[x] ; i ; i = e[i].next )
  90. {
  91. int y = e[i].ver;
  92. if ( y == f ) continue;
  93. dfs1( y , x , depth+1 );
  94. size[x] += size[y];
  95. if ( size[y] > Max ) Max = size[y] , son[x] = y;
  96. }
  97. }
  98. inline void dfs2(int x,int Top)
  99. {
  100. id[x] = ++cnt , top[x] = Top;
  101. if ( !son[x] ) return;
  102. else dfs2( son[x] , Top );
  103. for ( int i = Head[x] ; i ; i = e[i].next )
  104. {
  105. int y = e[i].ver;
  106. if ( y == fa[x] || y == son[x] ) continue;
  107. dfs2( y , y );
  108. }
  109. }
  110. inline void modify_chain(int x,int y,int val)
  111. {
  112. while ( top[x] ^ top[y] )
  113. {
  114. if ( dep[top[x]] < dep[top[y]] ) swap( x , y );
  115. Tree.modify( 1 , id[top[x]] , id[x] , val );
  116. x = fa[top[x]];
  117. }
  118. if ( dep[x] > dep[y] ) swap( x , y );
  119. Tree.modify( 1 , id[x] , id[y] , val );
  120. }
  121. inline int query_chain(int x,int y)
  122. {
  123. int res = 0;
  124. while ( top[x] ^ top[y] )
  125. {
  126. if ( dep[top[x]] < dep[top[y]] ) swap( x , y );
  127. res = ( res + Tree.query( 1 , id[top[x]] , id[x] ) ) % Mod;
  128. x = fa[top[x]];
  129. }
  130. if ( dep[x] > dep[y] ) swap( x , y );
  131. return ( res + Tree.query( 1 , id[x] , id[y] ) ) % Mod;
  132. }
  133. inline bool compare(query p1,query p2) { return p1.r < p2.r; }
  134. inline void solve(void)
  135. {
  136. int p = 0;
  137. for ( int i = 1 ; i <= tot ; i++ )
  138. {
  139. while ( p < a[i].r ) modify_chain( 1 , ++p , 1 );
  140. ans[ a[i].id ] += a[i].f * query_chain( 1 , a[i].z );
  141. ans[ a[i].id ] = ( ans[ a[i].id ] % Mod + Mod ) % Mod;
  142. }
  143. }
  144. int main(void)
  145. {
  146. input();
  147. dfs1( 1 , 0 , 1 );
  148. dfs2( 1 , 1 );
  149. Tree.build( 1 , 1 , n );
  150. sort( a+1 , a+tot+1 , compare );
  151. solve();
  152. for (int i=1;i<=m;i++)
  153. printf("%d\n",ans[i]);
  154. return 0;
  155. }

<后记>

『LCA 树链剖分』的更多相关文章

  1. Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)

    Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)↗[GO!] 题意 是说有棵树,每个节点上 ...

  2. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

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

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

  4. Codeforces Round #329 (Div. 2) D. Happy Tree Party LCA/树链剖分

    D. Happy Tree Party     Bogdan has a birthday today and mom gave him a tree consisting of n vertecie ...

  5. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  6. [CodeVS2370] 小机房的树 (LCA, 树链剖分, LCT)

    Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花 ...

  7. BZOJ3626[LNOI2014]LCA——树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  8. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...

  9. LCA树链剖分

    LCA(Lowest Common Ancestor 最近公共祖先)定义如下:在一棵树中两个节点的LCA为这两个节点所有的公共祖先中深度最大的节点. 比如这棵树 结点5和6的LCA是2,12和7的LC ...

随机推荐

  1. python—字符串拼接三种方法

    python—字符串拼接三种方法   1.使用加号(+)号进行拼接 字符串拼接直接进行相加就可以,比较容易理解,但是一定要记得,变量直接相加,不是变量就要用引号引起来,不然会出错,另外数字是要转换为字 ...

  2. InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's

    InvalidOperationException: Operations that change non-concurrent collections must have exclusive acc ...

  3. Python 二维码制作

    Python 二维码制作 先介绍python 二维码制作的第三方库 QRCode .MyQR QRCode    生成这个二维码只用三行 import qrcode img = qrcode.make ...

  4. C# Net 去除图片白边

    代码根据别人的进行改写,效果更好 直接拷贝使用 名称空间: using System.Drawing; 代码: /// <summary> /// 裁剪图片(去掉百边) /// </ ...

  5. Robot Framework RIDE介绍

    快捷键 F8 -执行测试用例 F5 -查看关键字 Edit标签 测试项目和测试套件所提供的Edit标签是一致的,两者功能也一样.

  6. 一个从tensorflow_1.14.0-gpu-py3-jupyter镜像生成公司实际需求的Dockerfile

    外部的标准镜像,肯定满足不了公司的实际要求咯~~ 所以,根据同事的需求,重新制作了这个包. 其中可用库为tensorflow,numpy, pandas,scikit-learn,jieba,gens ...

  7. 关于ID命名 一个页面唯一

    1.一般ID在一个区域内必须是唯一的.这样是一个规范而且在IE中使用JS通过ID获取这个对象永远只能获取第一个. 2.js无法找到重复的ID,用js获取时,只能得到第一个ID元素,但,如果不同的区域范 ...

  8. logging.basicConfig配置文件

    import sys, logging logging.basicConfig(level=logging.INFO, # 日志等级 # filename: 指定日志文件名 format='level ...

  9. face-api.js:一个在浏览器中进行人脸识别的 JavaScript 接口

    Mark! 本文将为大家介绍一个建立在「tensorflow.js」内核上的 javascript API——「face-api.js」,它实现了三种卷积神经网络架构,用于完成人脸检测.识别和特征点检 ...

  10. python--协程知识初识

    线程和进程的操作是由程序触发系统接口,最后的执行者是系统:协程的操作则是程序员. 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续).协程 ...