D. Misha, Grisha and Underground

这个题目算一个树链剖分的裸题,但是这个时间复杂度注意优化。

这个题目可以选择树剖+线段树,时间复杂度有点高,比较这个本身就有n*logn*logn

但是就是lca+一点点思维就完全不卡时间。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <iostream>
  5. #include <algorithm>
  6. #include <cstdlib>
  7. #include <vector>
  8. #include <stack>
  9. #include <map>
  10. #include <string>
  11. #define inf 0x3f3f3f3f
  12. #define inf64 0x3f3f3f3f3f3f3f3f
  13. using namespace std;
  14. const int maxn = 2e5 + 10;
  15.  
  16. int f[maxn];//f 保存u的父亲节点
  17. int dep[maxn];//dep保存节点u 的深度
  18. int siz[maxn];//siz保存以u为根的子节点的个数
  19. int son[maxn];//son 保存u的重儿子
  20. int rk[maxn];//rk当前dfs序在树中所对应的节点
  21. int top[maxn];// top保存当前结点所在链的顶端结点
  22. int id[maxn];//dfs的执行顺序
  23.  
  24. int a[maxn];
  25. int n;
  26. int sum[maxn * 4], lazy[maxn * 4];
  27. //------------------线段树部分---------------//
  28. void push_up(int id) {
  29. sum[id] = (sum[id << 1] + sum[id << 1 | 1]);
  30. }
  31.  
  32. void build(int id, int l, int r) {
  33. lazy[id] = -1;
  34. sum[id] = 0;
  35. if (l == r) return;
  36. int mid = (l + r) >> 1;
  37. build(id << 1, l, mid);
  38. build(id << 1 | 1, mid + 1, r);
  39. push_up(id);
  40. }
  41.  
  42. void push_down(int id, int len1, int len2) {
  43. if (lazy[id] == -1) return;
  44. lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
  45. sum[id << 1] = len1 * lazy[id];
  46. sum[id << 1 | 1] = len2 * lazy[id];
  47. lazy[id] = -1;
  48. }
  49.  
  50. void update(int id, int l, int r, int x, int y, int val) {
  51. // printf("id=%d l=%d r=%d x=%d y=%d val=%d\n", id, l, r, x, y, val);
  52. if (x <= l && y >= r) {
  53. sum[id] = (r - l + 1)*val;
  54. lazy[id] = val;
  55. return;
  56. }
  57. int mid = (l + r) >> 1;
  58. push_down(id, mid - l + 1, r - mid);
  59. if (x <= mid) update(id << 1, l, mid, x, y, val);
  60. if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, val);
  61. push_up(id);
  62. }
  63.  
  64. int query(int id, int l, int r, int x, int y) {
  65. if (x <= l && y >= r) return sum[id];
  66. int mid = (l + r) >> 1, ans = 0;
  67. push_down(id, mid - l + 1, r - mid);
  68. if (x <= mid) ans = (ans + query(id << 1, l, mid, x, y));
  69. if (y > mid) ans = (ans + query(id << 1 | 1, mid + 1, r, x, y));
  70. return ans;
  71. }
  72.  
  73. //------------------------树链剖分-------------------//
  74. // int f[maxn];//f 保存u的父亲节点
  75. // int dep[maxn];//dep保存节点u 的深度
  76. // int siz[maxn];//siz保存以u为根的子节点的个数
  77. // int son[maxn];//son 保存u的重儿子
  78. // int rk[maxn];//rk当前dfs序在树中所对应的节点
  79. // int top[maxn];// top保存当前结点所在链的顶端结点
  80. // int id[maxn];//dfs的执行顺序
  81. struct node {
  82. int v, nxt;
  83. node(int v = 0, int nxt = 0) :v(v), nxt(nxt) {}
  84. }ex[maxn];
  85. int head[maxn], cnt = 0, tot;
  86. void init() {
  87. cnt = 0, tot = 0;
  88. memset(son, 0, sizeof(son));
  89. memset(head, -1, sizeof(head));
  90. }
  91. void add(int u, int v) {
  92. ex[cnt] = node(v, head[u]);
  93. head[u] = cnt++;
  94. ex[cnt] = node(u, head[v]);
  95. head[v] = cnt++;
  96. }
  97.  
  98. void dfs1(int u, int fa, int depth) {
  99. f[u] = fa; dep[u] = depth; siz[u] = 1;
  100. for (int i = head[u]; i != -1; i = ex[i].nxt) {
  101. int v = ex[i].v;
  102. if (v == fa) continue;
  103. dfs1(v, u, depth + 1);
  104. siz[u] += siz[v];
  105. if (siz[v] > siz[son[u]]) son[u] = v;
  106. }
  107. }
  108.  
  109. void dfs2(int u, int t) {
  110. top[u] = t;
  111. id[u] = ++tot;//标记dfs序
  112. rk[tot] = u;//序号tot对应的结点u
  113. if (!son[u]) return;
  114. dfs2(son[u], t);
  115. /*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
  116. 一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
  117. for (int i = head[u]; i != -1; i = ex[i].nxt) {
  118. int v = ex[i].v;
  119. if (v != son[u] && v != f[u]) dfs2(v, v);//一个点位于轻链底端,那么它的top必然是它本身
  120. }
  121. }
  122.  
  123. void update2(int x, int y, int z)//修改x到y路径的值
  124. {
  125. // printf("x=%d y=%d %d %d\n", x, y, top[x], top[y]);
  126. while (top[x] != top[y])//不在同一条链上
  127. {
  128. // printf("%d %d\n", id[top[x]], id[x]);
  129. if (dep[top[x]] < dep[top[y]]) swap(x, y);//x为深度大的链
  130. update(1, 1, n, id[top[x]], id[x], z);//x为深度大的链
  131. x = f[top[x]];//深度大的向上跳
  132. }
  133. if (dep[x] > dep[y]) swap(x, y); //这里x和y在同一条链
  134. // printf("id[%d]=%d id[%d]=%d\n", x, id[x], y, id[y]);
  135. update(1, 1, n, id[x], id[y], z); //x和y这条链的更新
  136. }
  137.  
  138. int query2(int x, int y) {
  139. int ret = 0;
  140. while (top[x] != top[y]) {
  141. if (dep[top[x]] < dep[top[y]]) swap(x, y);
  142. ret = (ret + query(1, 1, n, id[top[x]], id[x]));
  143. x = f[top[x]];
  144. }
  145. if (dep[x] > dep[y]) swap(x, y);
  146. ret = (ret + query(1, 1, n, id[x], id[y]));
  147. return ret;
  148. }
  149.  
  150. //------------------树链剖分结束-------------------//
  151.  
  152. int main() {
  153. init();
  154. int m, x;
  155. scanf("%d%d", &n, &m);
  156. for (int i = 2; i <= n; i++) scanf("%d", &x), add(x, i);
  157. dfs1(1, -1, 1), dfs2(1, 1);
  158. build(1, 1, n);
  159. // for (int i = 1; i <= n; i++) printf("id[%d]=%d\n", i, id[i]);
  160. while (m--) {
  161. int l, r, c, ans = 0;
  162. scanf("%d%d%d", &l, &r, &c);
  163. // printf("l=%d r=%d c=%d\n", l, r, c);
  164. update2(r, l, 1);
  165. ans = max(ans, query2(c, l));
  166. ans = max(ans, query2(c, r));
  167. update(1, 1, n, 1, n, 0);
  168.  
  169. update2(c, l, 1);
  170. ans = max(ans, query2(r, l));
  171. ans = max(ans, query2(r, c));
  172. update(1, 1, n, 1, n, 0);
  173.  
  174. update2(r, c, 1);
  175. ans = max(ans, query2(l, c));
  176. ans = max(ans, query2(l, r));
  177. update(1, 1, n, 1, n, 0);
  178.  
  179. printf("%d\n", ans);
  180. }
  181. return 0;
  182. }

  

D. Misha, Grisha and Underground 树链剖分的更多相关文章

  1. Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

    Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...

  2. 树链剖分 + 后缀数组 - E. Misha and LCP on Tree

    E. Misha and LCP on Tree Problem's Link Mean: 给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. analyse: ...

  3. CF 504E Misha and LCP on Tree(树链剖分+后缀数组)

    题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...

  4. CF 504E Misha and LCP on Tree——后缀数组+树链剖分

    题目:http://codeforces.com/contest/504/problem/E 树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组. 对于询 ...

  5. CF504E Misha and LCP on Tree(树链剖分+后缀树组)

    1A真舒服. 喜闻乐见的树链剖分+SA. 一个初步的想法就是用树链剖分,把两个字符串求出然后hash+二分求lcp...不存在的. 因为考虑到这个字符串是有序的,我们需要把每一条重链对应的字符串和这个 ...

  6. CF504E Misha and LCP on Tree 后缀自动机+树链剖分+倍增

    求树上两条路径的 LCP (树上每个节点代表一个字符) 总共写+调了6个多小时,终于过了~ 绝对是我写过的最复杂的数据结构了 我们对这棵树进行轻重链剖分,然后把所有的重链分正串,反串插入到广义后缀自动 ...

  7. Codeforces Round #425 (Div. 2) Misha, Grisha and Underground(LCA)

    Misha, Grisha and Underground time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  8. Codeforecs Round #425 D Misha, Grisha and Underground (倍增LCA)

    D. Misha, Grisha and Underground time limit per test 2 seconds memory limit per test 256 megabytes i ...

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

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

随机推荐

  1. CVE-2019-0193 远程命令执行-漏洞复现

    0x01 漏洞简介 Apache Solr 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.此次漏洞出现在Apache Solr的 ...

  2. Spring Cloud和eureka启动报错 解决版本依赖关系

    导读 An attempt was made to call a method that does not exist. The attempt was made from the following ...

  3. 【翻译】创建String 使用“”还是构造函数(new String)

    在java中创建String,通常有以下两种方法. String x = "abc"; String y = new String("abc"); 它们之间有什 ...

  4. Oracle NULL值

    NULL值,用来描述记录中没有定义内容的字段值.在Oracle中,判断某个条件的值时,返回值可能是TRUE.FALSE或UNKNOWN. 如果查询一个列的值是否等于20,而该列的值为NULL,那么就是 ...

  5. stand up meeting 1/18/2016

    part 组员                工作              工作耗时/h 明日计划 工作耗时/h    UI 冯晓云  准备最后的发布和整个开发的整理总结    6 release ...

  6. Daily Scrum 12/18/2015

    Process: Zhaoyang: Some IOS UI upgrade to increase the users' experience. Minlong: Build a restful s ...

  7. F - Make It Equal CodeForces - 1065C

    题目大意:有n座塔,塔高h[i],每次给定高度H对他们进行削切,要求每次削掉的所有格子数不能超过k个,输出最少削几次才能使所有塔的高度相同. 思路一:差分+贪心 对于每一个高度h,用一个数组让1~h的 ...

  8. LCA基础 附例题(落谷)

    https://www.luogu.org/problemnew/solution/P3379 LCA叫做最短公共祖先,用来求距离树上两个节点最近的公共点: 常用倍增算法: #include<i ...

  9. 14. 最长公共前缀----LeetCode

    编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...

  10. Kaggle入门——泰坦尼克号生还者预测

    前言 这个是Kaggle比赛中泰坦尼克号生存率的分析.强烈建议在做这个比赛的时候,再看一遍电源<泰坦尼克号>,可能会给你一些启发,比如妇女儿童先上船等.所以是否获救其实并非随机,而是基于一 ...