Brief Description

给定一颗有根树(根为1),有以下

两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个

结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖

先)你能帮帮他吗?

Algorithm Design

树链剖分维护最深层带标记节点.

裸, 1A, 高兴.

Code

  1. #include <cstdio>
  2. #define init int l = t[k].l, r = t[k].r, mid = (l + r) >> 1
  3. const int maxn = 201000;
  4. int n, Q, cnt;
  5. struct edge {
  6. int to, next;
  7. } e[maxn << 1];
  8. struct seg {
  9. int l, r, data;
  10. } t[maxn << 2];
  11. int head[maxn], q[maxn], bl[maxn], belong[maxn], size[maxn], dfn, like[maxn],
  12. tag[maxn], fa[maxn], deep[maxn];
  13. void add_edge(int u, int v) {
  14. e[++cnt].to = v;
  15. e[cnt].next = head[u];
  16. head[u] = cnt;
  17. }
  18. void dfs1(int x) {
  19. size[x] = 1;
  20. for (int i = head[x]; i; i = e[i].next) {
  21. if (e[i].to != fa[x]) {
  22. fa[e[i].to] = x;
  23. deep[e[i].to] = deep[x] + 1;
  24. dfs1(e[i].to);
  25. size[x] += size[e[i].to];
  26. if (size[e[i].to] > size[like[x]])
  27. like[x] = e[i].to;
  28. }
  29. }
  30. }
  31. void dfs2(int x, int chain) {
  32. bl[x] = ++dfn;
  33. q[dfn] = x;
  34. belong[x] = chain;
  35. if (like[x])
  36. dfs2(like[x], chain);
  37. for (int i = head[x]; i; i = e[i].next) {
  38. if (e[i].to != fa[x] && e[i].to != like[x]) {
  39. dfs2(e[i].to, e[i].to);
  40. }
  41. }
  42. }
  43. void build(int k, int l, int r) {
  44. t[k].l = l, t[k].r = r, t[k].data = (l <= 1 && 1 <= r) ? 1 : 0;
  45. if (l == r)
  46. return;
  47. int mid = (l + r) >> 1;
  48. build(k << 1, l, mid);
  49. build(k << 1 | 1, mid + 1, r);
  50. }
  51. void update(int k) {
  52. t[k].data = t[k << 1 | 1].data ? t[k << 1 | 1].data : t[k << 1].data;
  53. }
  54. void modify(int k, int pos, int val) {
  55. init;
  56. if (l == r) {
  57. if (deep[val] > deep[t[k].data])
  58. t[k].data = val;
  59. return;
  60. }
  61. if (pos <= mid)
  62. modify(k << 1, pos, val);
  63. else
  64. modify(k << 1 | 1, pos, val);
  65. update(k);
  66. }
  67. int query(int k, int x, int y) {
  68. init;
  69. if (x <= l && r <= y) {
  70. return t[k].data;
  71. }
  72. int ans = 0;
  73. if (x <= mid) {
  74. int t = query(k << 1, x, y);
  75. if (deep[t] > deep[ans])
  76. ans = t;
  77. }
  78. if (y > mid) {
  79. int t = query(k << 1 | 1, x, y);
  80. if (deep[t] > deep[ans])
  81. ans = t;
  82. }
  83. return ans;
  84. }
  85. void ask(int x, int f) {
  86. int ans = 0;
  87. while (belong[x] != belong[f]) {
  88. int t = query(1, bl[belong[x]], bl[x]);
  89. ans = t ? t : 0;
  90. if (ans)
  91. break;
  92. x = fa[belong[x]];
  93. }
  94. int t = query(1, bl[belong[x]], bl[x]);
  95. ans = t ? t : 0;
  96. printf("%d\n", ans);
  97. }
  98. int main() {
  99. #ifndef ONLINE_JUDGE
  100. freopen("input", "r", stdin);
  101. #endif
  102. scanf("%d %d", &n, &Q);
  103. deep[0] = -1;
  104. for (int i = 1; i < n; i++) {
  105. int x, y;
  106. scanf("%d %d", &x, &y);
  107. add_edge(x, y);
  108. add_edge(y, x);
  109. }
  110. dfs1(1);
  111. dfs2(1, 1);
  112. build(1, 1, dfn);
  113. while (Q--) {
  114. char op[5];
  115. scanf("%s", op);
  116. if (op[0] == 'Q') {
  117. int x;
  118. scanf("%d", &x);
  119. ask(x, 1);
  120. } else {
  121. int x;
  122. scanf("%d", &x);
  123. tag[x] = 1;
  124. modify(1, bl[x], x);
  125. }
  126. }
  127. }

[bzoj4551][Tjoi2016&Heoi2016]树-树链剖分的更多相关文章

  1. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  2. [BZOJ4551][TJOI2016&&HEOI2016]树(并查集)

    4551: [Tjoi2016&Heoi2016]树 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1746  Solved: 800[Sub ...

  3. bzoj4553 [Tjoi2016&Heoi2016]序列 树状数组(区间最大值)+cqd

    [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1006  Solved: 464[Submit][ ...

  4. 线段树&数链剖分

    傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...

  5. BZOJ4551 Tjoi2016&Heoi2016树(离线+并查集)

    似乎是弱化的qtree3.树剖什么的非常无脑.考虑离线.并查集维护每个点的最近打标记祖先,倒序处理,删除标记时将其与父亲合并即可. #include<iostream> #include& ...

  6. BZOJ4551——[Tjoi2016&Heoi2016]树

    1.题意: 给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个 结点,可以打多次标记.)2. 询问操作:询问某个 ...

  7. [bzoj4551][Tjoi2016][Heoi2016]树

    Description 在2016年,佳媛姐姐刚刚学习了树,非常开心. 现在她想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作: 1. 标记操作:对某个结点打上标记(在最开始,只有结点1有 ...

  8. BZOJ4551: [Tjoi2016&Heoi2016]树

    Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标 ...

  9. BZOJ4553: [Tjoi2016&Heoi2016]序列 树套树优化DP

    把pos[i]上出现的平常值定义为nor[i]最大值定义为max[i]最小值定义为min[i],那么我们发现在两个值,i(前),j(后),当且仅当max[i]<=nor[j],nor[i]< ...

随机推荐

  1. 003_JS基础_面向对象基础

    3.1 对象   引入:在js中表示一个人的信息(name, gender, age)通过var申明三个变量,但是这样使用基本数据类型的变量,他们是互相独立的,没有联系:  此时就需要使用对象,对象是 ...

  2. 【开发技术】Beyond Compare

    黑色表示左右两侧的文件(夹)是一样的; 紫色表示右(左)侧是完全没有的,这时我们右击这个文件(夹),选择“复制到右(左)侧”即可: 红色表示两边都有这个文件(夹),但不完全相同,这时你就要权衡一下修改 ...

  3. 关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    我们最初学习计算机的时候,都学过ASCII编码. 但是为了表示各种各样的语言,在计算机技术的发展过程中,逐渐出现了很多不同标准的编码格式, 重要的有Unicode.UTF.ISO-8859-1和中国人 ...

  4. MySQL 多版本并发控制(MVCC)

    可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁的操作,因此开销会很低.主要实现的是非阻塞的读操作,写操作也只是锁定必要的行.MVCC的实现是通过保存数据在某个时间点的快照来实现的,也 ...

  5. python2.7.5 安装pip

    1 先安装setuptools 下载地址:https://pypi.python.org/pypi/setuptools#downloads 将下载后的tar文件解压,用CMD模式进入到解压后的文件所 ...

  6. Log4j扩展使用--输出地Appender

    OK,现在我们来研究输出低Appended. Appender控制日志输出的位置 Log4j日志系统允许把日志输出到不同的地方,如控制台(Console).文件(Files).根据天数或者文件大小产生 ...

  7. Java多线程之线程其他类

    Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...

  8. jdbc参数

    JDBC连接池参数:    jdbc.initialSize=0       //初始化连接    jdbc.maxActive=30     //连接池的最大数据库连接数,设为0表示无限制    j ...

  9. MySQL模糊查询中通配符的转义

    sql中经常用like进行模糊查询,而模糊查询就要用到百分号“%”,下划线“_”这些通配符,其中“%”匹配任意多个字符,“_”匹配单个字符.如果我们想要模糊查询带有通配符的字符串,如“60%”,“us ...

  10. Android 使用android-support-multidex解决Dex超出方法数的限制问题

    随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LE ...