(题面来自luogu)

题意翻译

你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]。

有两种操作:

1 v c 将以v为根的子树中所有点颜色更改为c

2 v 查询以v为根的子树中的节点有多少种不同的颜色

翻译贡献者UID:28455

n、m <= 4e5,ci <= 60。

  今天唯一听懂的一道题目,调了两个小时……因为要查询子树信息,考虑构造出dfs序之后,用线段树维护区间颜色。因为颜色只有60种,可以维护在节点上维护bitset或者一个64位整型来压缩状态,每一位上表示以该点为根的子树内是否含有这个颜色。

  线段树内的tag是不可以累加的,每个tag都是一次直接修改,因此要在下推时特判掉空的无效标记。

代码:

  1. #include <bitset>
  2. #include <cstdio>
  3. #include <iostream>
  4. #define maxn 400010
  5. using namespace std;
  6. template <typename T>
  7. void read(T &x) {
  8. x = 0;
  9. int f = 1;
  10. char ch = getchar();
  11. while (!isdigit(ch)) {
  12. if (ch == '-')
  13. f = -1;
  14. ch = getchar();
  15. }
  16. while (isdigit(ch)) {
  17. x = x * 10 + (ch ^ 48);
  18. ch = getchar();
  19. }
  20. x *= f;
  21. return;
  22. }
  23. int n, m;
  24. struct E {
  25. int to, nxt;
  26. } edge[maxn << 1];
  27. int head[maxn], top;
  28. inline void insert(int u, int v) {
  29. edge[++top] = (E) {v, head[u]};
  30. head[u] = top;
  31. }
  32. int color[maxn], val[maxn], dfn[maxn], size[maxn], tmr;
  33. void dfs(int u, int pre) {
  34. dfn[u] = ++tmr;
  35. size[u] = 1;
  36. val[tmr] = color[u];
  37. for (int i = head[u]; i; i = edge[i].nxt) {
  38. int v = edge[i].to;
  39. if (v != pre) {
  40. dfs(v, u);
  41. size[u] += size[v];
  42. }
  43. }
  44. }
  45. namespace Segment_tree {
  46. #define lc (nd<<1)
  47. #define rc ((nd<<1)|1)
  48. #define mid ((l + r) >> 1)
  49. bitset<61> seg[maxn << 2];
  50. bitset<61> tag[maxn << 2];
  51. inline void put_tag(int nd, bitset<61> op) {
  52. if (op.count()) //关键,以及第一个调炸的点
  53. seg[nd] = op,
  54. tag[nd] = op;
  55. }
  56. inline void push_down(int nd) {
  57. put_tag(lc, tag[nd]);
  58. put_tag(rc, tag[nd]);
  59. tag[nd].reset();//第二个调炸的点:忘记清除标记
  60. }
  61. inline void update(int nd) {
  62. seg[nd] = seg[lc] | seg[rc];
  63. }
  64. void build(int nd, int l, int r) {
  65. if (l == r) {
  66. seg[nd].set(val[l], 1);
  67. return;
  68. }
  69. build(lc, l, mid);
  70. build(rc, mid + 1, r);
  71. update(nd);
  72. }
  73. void modify(int nd, int l, int r, int ql, int qr, bitset<61> op) {
  74. if (l >= ql && r <= qr) {
  75. put_tag(nd, op);
  76. return;
  77. } else if (l > qr || r < ql)
  78. return;
  79. push_down(nd);
  80. modify(lc, l, mid, ql, qr, op);
  81. modify(rc, mid + 1, r, ql, qr, op);
  82. update(nd);
  83. }
  84. bitset<61> query(int nd, int l, int r, int ql, int qr) {
  85. if (l >= ql && r <= qr)
  86. return seg[nd];
  87. if (l > qr || r < ql) {
  88. bitset<61> t;
  89. return t;
  90. }
  91. push_down(nd);
  92. return query(lc, l, mid, ql, qr) | query(rc, mid + 1, r, ql, qr);
  93. }
  94. } using namespace Segment_tree;
  95. int main() {
  96. read(n), read(m);
  97. for (int i = 1; i <= n; ++i)
  98. read(color[i]);
  99. int u, v, t, k;
  100. for (int i = 1; i < n; ++i) {
  101. read(u), read(v);
  102. insert(u, v), insert(v, u);
  103. }
  104. dfs(1, 0);
  105. build(1, 1, n);
  106. bitset<61> op;
  107. for (int i = 1; i <= m; ++i) {
  108. read(t), read(v);
  109. if (t == 1) {
  110. read(k);
  111. op.reset();
  112. op.set(k, 1);
  113. modify(1, 1, n, dfn[v], dfn[v] + size[v] - 1, op);
  114. } else {
  115. op = query(1, 1, n, dfn[v], dfn[v] + size[v] - 1);
  116. printf("%d\n", op.count());
  117. }
  118. }
  119. return 0;
  120. }

最新文章

  1. IE6 跟随滚动解决方法
  2. 如何使用BHO定制你的Internet Explorer浏览器
  3. 【Java每日一题】20161019
  4. Mastering Web Application Development with AngularJS 读书笔记-前记
  5. SQL疑难杂症【4 】大量数据查询的时候避免子查询
  6. python3 对文件的查找、替换、删除
  7. C语言中结构体 自引用 和 相互引用
  8. Kinect For Windows V2开发日志五:使用OpenCV显示彩色图像及红外图像
  9. (四)学习CSS之position、bottom、left、right和top属性
  10. [Javascript] Drawing Styles on HTML5 Canvas
  11. 详解QUiLoader 动态加载.ui文件
  12. Rational Rose 7.0的使用(转)
  13. Delphi之通过代码示例学习XML解析、StringReplace的用法(异常控制 good)
  14. SQL 建表 插数据
  15. session的一些方法
  16. 支付宝app支付服务器签名代码(C#)
  17. 【Kafka源码】ReplicaManager启动过程
  18. 读取Excel,单元格内容大于255个字符自动被截取的问题
  19. C# 后台访问webapi
  20. TOP100summit:【分享实录-猫眼电影】业务纵横捭阖背后的技术拆分与融合

热门文章

  1. 三分钟带你分清Mysql 和Oracle之间的误区
  2. 基于PHP实现短信验证码接口的方法
  3. Linux 系统编程 学习:01-进程的有关概念 与 创建、回收
  4. 基于SLF4J的MDC机制和Dubbo的Filter机制,实现分布式系统的日志全链路追踪
  5. Git--gitLab远程仓库分支代码回退的两种方案
  6. Layui弹出层详解
  7. 1+X云计算平台运维与开发(中级)eNSP A~E卷 试题+答案
  8. nat+端口转发,使得宿主机secureCRT可以访问vbox里linux虚拟机
  9. Docker - 解决同步容器与主机时间报错:Error response from daemon: Error processing tar file(exit status 1): invalid symlink &quot;/usr/share/zoneinfo/UTC&quot; -&gt; &quot;../usr/share/zoneinfo/Asia/Shanghai&quot;
  10. 这个Map你肯定不知道,毕竟存在感确实太低了。