这题好神啊

能够\(1A\)真是不可思议

首先看到要求的这个柿子\(\sum_{i=l}^{r}deep[LCA(i,z)]\),而且\(l\)和\(r\)并不是来自与一棵子树或者一条链,而是编号连续的一段

所以肯定没有什么办法可以一下子求出来这么多的\(LCA\)的

得想个好的办法转化一下

于是就想往主席树上想

首先\(z\)的\(lca\)肯定是在\(z\)到根的路径上的,于是我们可以定住\(lca\),来求这个\(lca\)对答案的贡献

于是我们有一个主席树的暴力

我们就枚举\(z\)到根的路径上的点,对于这些每一个点,我们求出在其子树内部有多少个大于\(l\)小于\(r\)的点,乘上深度,这就是这个\(lca\)的贡献

吗?

显然不是,我们得减去那些在下面的那些子树里就已经算过了的数

所以我们会暴力啦,真开心

那我们想一下如何优化暴力

先来看看答案长什么样子

好吧,我画的还是很难看,这可是魏佬钦定

我们设\(sum_i\)表示在\(i\)的子树内部有多少个符合条件的点

于是我们的答案可以写成

\[4*sum_4+3*(sum_3-sum_4)+2*(sum_2-sum_3)+1*(sum_1-sum_2)
\]

之后就会惊奇的发现答案竟然就是\(sum_4+sum_3+sum_2+sum_1\)

那我们怎么维护啊,难道要硬上主席树?

显然不用啊

既然没有强制在线,我们就离线+树剖呗

一个点显然只会对他本身到根上这条路径的点产生贡献,于是就是一个树剖板子了

同时查询也是一个简单的根路径查询

至于如何统计答案,我们将询问排序,之后可以将插入顺序想象成时间轴,于是就可以差分求解了

代码

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #define re register
  6. #define maxn 50005
  7. const int mod=201314;
  8. struct E
  9. {
  10. int v,nxt;
  11. }e[maxn<<1];
  12. struct Ask
  13. {
  14. int x,y,z,rk;
  15. }a[maxn];
  16. int n,m,num,Q,cnt;
  17. int top[maxn],deep[maxn],fa[maxn],to[maxn],sum[maxn],son[maxn],head[maxn];
  18. int l[maxn<<2],r[maxn<<2],tag[maxn<<2],d[maxn<<2];
  19. int Lans[maxn],Rans[maxn];
  20. inline void add_edge(int x,int y)
  21. {
  22. e[++num].v=y;
  23. e[num].nxt=head[x];
  24. head[x]=num;
  25. }
  26. inline int read()
  27. {
  28. char c=getchar();
  29. int x=0;
  30. while(c<'0'||c>'9') c=getchar();
  31. while(c>='0'&&c<='9')
  32. x=(x<<3)+(x<<1)+c-48,c=getchar();
  33. return x;
  34. }
  35. void build(int x,int y,int i)
  36. {
  37. l[i]=x,r[i]=y,d[i]=0,tag[i]=0;
  38. if(x==y) return;
  39. int mid=x+y>>1;
  40. build(x,mid,i<<1),build(mid+1,y,i<<1|1);
  41. }
  42. inline void pushdown(int i)
  43. {
  44. if(!tag[i]) return;
  45. tag[i<<1]+=tag[i];
  46. if(tag[i<<1]>mod) tag[i<<1]%=mod;
  47. tag[i<<1|1]+=tag[i];
  48. if(tag[i<<1|1]>mod) tag[i<<1|1]%=mod;
  49. d[i<<1]+=(r[i<<1]-l[i<<1]+1)*tag[i];
  50. d[i<<1]%=mod;
  51. d[i<<1|1]+=(r[i<<1|1]-l[i<<1|1]+1)*tag[i];
  52. d[i<<1|1]%=mod;
  53. tag[i]=0;
  54. }
  55. void change(int x,int y,int i)
  56. {
  57. if(x<=l[i]&&y>=r[i])
  58. {
  59. tag[i]++;
  60. d[i]+=r[i]-l[i]+1;
  61. if(d[i]>mod) d[i]%=mod;
  62. return;
  63. }
  64. pushdown(i);
  65. int mid=l[i]+r[i]>>1;
  66. if(y<=mid) change(x,y,i<<1);
  67. else if(x>mid) change(x,y,i<<1|1);
  68. else change(x,y,i<<1),change(x,y,i<<1|1);
  69. d[i]=(d[i<<1]+d[i<<1|1])%mod;
  70. }
  71. int query(int x,int y,int i)
  72. {
  73. if(x<=l[i]&&y>=r[i]) return d[i];
  74. pushdown(i);
  75. int mid=l[i]+r[i]>>1;
  76. if(y<=mid) return query(x,y,i<<1);
  77. if(x>mid) return query(x,y,i<<1|1);
  78. return (query(x,y,i<<1)+query(x,y,i<<1|1))%mod;
  79. }
  80. void dfs1(int x)
  81. {
  82. sum[x]=1;
  83. int maxx=-1;
  84. for(re int i=head[x];i;i=e[i].nxt)
  85. if(!deep[e[i].v])
  86. {
  87. deep[e[i].v]=deep[x]+1;
  88. fa[e[i].v]=x;
  89. dfs1(e[i].v);
  90. sum[x]+=sum[e[i].v];
  91. if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
  92. }
  93. }
  94. void dfs2(int x,int topf)
  95. {
  96. top[x]=topf;
  97. to[x]=++cnt;
  98. if(!son[x]) return;
  99. dfs2(son[x],topf);
  100. for(re int i=head[x];i;i=e[i].nxt)
  101. if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) dfs2(e[i].v,e[i].v);
  102. }
  103. inline void tree_change(int x,int y)
  104. {
  105. while(top[x]!=top[y])
  106. {
  107. if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
  108. change(to[top[x]],to[x],1);
  109. x=fa[top[x]];
  110. }
  111. if(deep[x]>deep[y]) std::swap(x,y);
  112. change(to[x],to[y],1);
  113. }
  114. inline int tree_query(int x,int y)
  115. {
  116. int ans=0;
  117. while(top[x]!=top[y])
  118. {
  119. if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
  120. ans+=query(to[top[x]],to[x],1);
  121. if(ans>mod) ans%=mod;
  122. x=fa[top[x]];
  123. }
  124. if(deep[x]>deep[y]) std::swap(x,y);
  125. ans+=query(to[x],to[y],1);
  126. return ans%mod;
  127. }
  128. inline int cmp(Ask K,Ask M)
  129. {
  130. return K.x<M.x;
  131. }
  132. inline int cop(Ask K,Ask M)
  133. {
  134. return K.y<M.y;
  135. }
  136. int main()
  137. {
  138. n=read(),Q=read();
  139. int Fa;
  140. for(re int i=1;i<n;i++)
  141. Fa=read(),add_edge(Fa,i);
  142. deep[0]=1;
  143. dfs1(0);
  144. dfs2(0,0);
  145. build(1,n,1);
  146. for(re int i=1;i<=Q;i++)
  147. a[i].x=read(),a[i].y=read(),a[i].z=read(),a[i].rk=i;
  148. std::sort(a+1,a+Q+1,cmp);
  149. int tot=1;
  150. for(re int i=-1;i<n;i++)
  151. {
  152. if(i>=0) tree_change(i,0);
  153. while(a[tot].x-1==i)
  154. {
  155. Lans[a[tot].rk]=tree_query(a[tot].z,0);
  156. tot++;
  157. }
  158. }
  159. build(1,n,1);
  160. std::sort(a+1,a+Q+1,cop);
  161. tot=1;
  162. for(re int i=0;i<n;i++)
  163. {
  164. tree_change(i,0);
  165. while(a[tot].y==i)
  166. {
  167. Rans[a[tot].rk]=tree_query(a[tot].z,0);
  168. tot++;
  169. }
  170. }
  171. for(re int i=1;i<=Q;i++)
  172. printf("%d\n",(Rans[i]-Lans[i]+mod)%mod);
  173. return 0;
  174. }

【[LNOI2014]LCA】的更多相关文章

  1. [SPOJ913]QTREE2 - Query on a tree II【倍增LCA】

    题目描述 [传送门] 题目大意 给一棵树,有两种操作: 求(u,v)路径的距离. 求以u为起点,v为终点的第k的节点. 分析 比较简单的倍增LCA模板题. 首先对于第一问,我们只需要预处理出根节点到各 ...

  2. 【Tarjan,LCA】【3-21个人赛】【problemD】

    Problem D Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Sub ...

  3. POJ3694 Network【连通分量+LCA】

    题意: 一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上). 思路: 首先运行一次Tarjan ...

  4. 【最小生成树+LCA】Imperial roads

    http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...

  5. 【Targan+LCA】HDU 3686 Traffic Real Time Query

    题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...

  6. 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树

    [BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...

  7. bzoj3626【LNOI2014】LCA

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1266  Solved: 448 [Submit][Stat ...

  8. 【POJ 3694】 Network(割边&lt;桥&gt;+LCA)

    [POJ 3694] Network(割边+LCA) Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7971 ...

  9. 【LCA】BZOJ1776-[Usaco2010 Hol]cowpol 奶牛政坛

    [题目大意] 一棵n个点的树,树上每个点属于一个党派,要求每个党派的最远距离点.两点间距离为两点间边的个数. [思路] yy一下可知,最远距离点中必有一个是该党派深度最深的一个,那么我们就记下最深的点 ...

随机推荐

  1. 如鹏网学习笔记(九)JavaScript

    JavaScript笔记 一.JavaScript简介 1,JavaScript是一种计算机编程语言,可以像等其他编程语言那样定义变量,执行循环等. 2,JavaScript代码主要执行在浏览器上,为 ...

  2. Quartz大致介绍(一)

    1. 介绍 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,是完全由java开发的一个开源的任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳 ...

  3. 非法关闭idea后报错,插件无法正常加载解决方法

    Problems found loading plugins: Plugin "GlassFish Integration" was not loaded: required pl ...

  4. groovy运行程序和类型推断

    在 Java 中,如果要声明一个 String 变量,则必须输入: String value = "Hello World"; 等号右侧的字符已经表明 value 的类型是 Str ...

  5. hdu 1075 What Are You Talking About 字典树模板

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  6. Win10系统安装vmware workstation 12后没有桥接网卡怎么办

    原文 vmware workstation是一款虚拟机计算机软件,可以同时运行不同的操作系统,然而有win10系统用户在安装vmware workstation 12之后,却发现网络连接里面没有桥接网 ...

  7. arguments 参数

    下面要写的是知识梳理的一个案例: 写一个求和的方法sumFn,不管传递的参数有什么,都能将最终的和算出来,并且返回给函数外部使用.(要求:一个参数都不传默认结果为0,对于传递的非正常数字的参数不与累加 ...

  8. TAT

    瞎扯 继\(HNOI,\)学科\(,CTSC, APIO\)连续爆炸之后 曾一度的怀疑人生,没有任何搞学习的欲望 不断的反省自己:我为什么这么菜? 然后回去搞学科,一直处于一个颓废的状态 后来得知\( ...

  9. Linux(Ubuntu16.04)下添加新用户

    某些情况下,Ubuntu 使用useradd 新用户名,在home 文件夹下面看不到新创建的用户文件夹,例如: 发现找不到,spark的文件夹,因此将采用下面方式重新建立首先删除spark用户 若想给 ...

  10. How do I use the API correctly

    1:打开帮助文档2:点击显示,找到索引,看到输入框3:你要学习什么内容,你就在框框里面输入什么内容 举例:Random4:看包 java.lang包下的类在使用的时候是不需要导包的5:看类的描述 Ra ...