题目链接

题意:

  给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作:

    1 u v:u到v路径(最短)上的边都取成相反的颜色

    2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一个节点在路径上)

    3 u v:查询u到v路径上有多少个黑色边

思路:

  对树进行树链剖分,分成重链和轻链,用两棵线段树W,L来维护。W维护树上在重链上的u和v之间的边的翻转情况(操作在线段树上的[pos[v],pos[u]]区间);L维护树上在重链上的u和v之间的相邻边的翻转情况。那么某一个点u与它父亲节点fa[u]的边的最终翻转情况为:W(pos[u], pos[u])(如果边是重链上的边),W(pos[u], pos[u])^L(pos[fa[u]], pos[fa[u]])(如果边是轻链)。对于1操作,只要简单的在W上维护就可以了。对于2操作,除了在L上操作,还要注意头和尾的特殊处理(因为对于重链内的点,不包括头尾,只在W上查询),也就是u的重链上的儿子son[u]以及u的链头p=belong[u]要在W上翻转一次,结合图可能更能理解。还有就是线段树的操作了。

另外:

  u可能没有son[u],默认为虚点0,那么在线段树上需要加上一句话:if (l == r) return ;

  1. #include <bits/stdc++.h>
  2.  
  3. const int N = 1e5 + 5;
  4.  
  5. //线段树
  6. #define lson l, mid, o << 1
  7. #define rson mid + 1, r, o << 1 | 1
  8. struct Seg_Tree {
  9. int fp[N<<2], s[N<<2];
  10. void flip(int l, int r, int o) {
  11. s[o] = (r - l + 1) - s[o];
  12. fp[o] ^= 1;
  13. }
  14. void push_up(int o) {
  15. s[o] = s[o<<1] + s[o<<1|1];
  16. }
  17. void push_down(int l, int r, int o) {
  18. if (fp[o]) {
  19. int mid = l + r >> 1;
  20. flip (lson);
  21. flip (rson);
  22. fp[o] = 0;
  23. }
  24. }
  25. void build(int l, int r, int o) {
  26. fp[o] = s[o] = 0;
  27. if (l == r) {
  28. return ;
  29. }
  30. int mid = l + r >> 1;
  31. build (lson);
  32. build (rson);
  33. }
  34. void updata(int ql, int qr, int l, int r, int o) {
  35. if (ql <= l && r <= qr) {
  36. flip (l, r, o);
  37. return ;
  38. }
  39. if (l == r) return ; //!
  40. push_down (l, r, o);
  41. int mid = l + r >> 1;
  42. if (ql <= mid) updata (ql, qr, lson);
  43. if (qr > mid) updata (ql, qr, rson);
  44. push_up (o);
  45. }
  46. int query(int ql, int qr, int l, int r, int o) {
  47. if (ql <= l && r <= qr) {
  48. return s[o];
  49. }
  50. push_down (l, r, o);
  51. int mid = l + r >> 1, ret = 0;
  52. if (ql <= mid) ret += query (ql, qr, lson);
  53. if (qr > mid) ret += query (ql, qr, rson);
  54. push_up (o);
  55. return ret;
  56. }
  57. }W, L;
  58.  
  59. std::vector<int> edge[N];
  60. int sz[N], dep[N], son[N], fa[N];
  61. int pos[N], belong[N];
  62. int loc;
  63. int n;
  64.  
  65. int query(int u, int v) {
  66. int p = belong[u], q = belong[v], ret = 0;
  67. while (p != q) {
  68. if (dep[p] < dep[q]) {
  69. std::swap (p, q);
  70. std::swap (u, v);
  71. }
  72. if (u != p) {
  73. ret += W.query (pos[son[p]], pos[u], 1, n, 1);
  74. }
  75. ret += (W.query (pos[p], pos[p], 1, n, 1) ^ L.query (pos[fa[p]], pos[fa[p]], 1, n, 1));
  76. u = fa[p];
  77. p = belong[u];
  78. }
  79.  
  80. if (u == v) return ret;
  81.  
  82. if (dep[u] < dep[v]) {
  83. std::swap (u, v);
  84. }
  85. ret += W.query (pos[son[v]], pos[u], 1, n, 1);
  86. return ret;
  87. }
  88.  
  89. void modify(int t, int u, int v) {
  90. int p = belong[u], q = belong[v];
  91. while (p != q) {
  92. if (dep[p] < dep[q]) {
  93. std::swap (p, q);
  94. std::swap (u, v);
  95. }
  96. if (t == 1) {
  97. W.updata (pos[p], pos[u], 1, n, 1);
  98. } else {
  99. L.updata (pos[p], pos[u], 1, n, 1);
  100. W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
  101. W.updata (pos[p], pos[p], 1, n, 1);
  102. }
  103. u = fa[p];
  104. p = belong[u];
  105. }
  106.  
  107. if (dep[u] < dep[v]) {
  108. std::swap (u, v);
  109. }
  110. if (t == 1) {
  111. if (u == v) return ;
  112. W.updata (pos[son[v]], pos[u], 1, n, 1);
  113. } else {
  114. L.updata (pos[v], pos[u], 1, n, 1);
  115. W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
  116. W.updata (pos[v], pos[v], 1, n, 1);
  117. }
  118. }
  119.  
  120. //树链剖分
  121. void DFS2(int u, int chain) {
  122. pos[u] = ++loc;
  123. belong[u] = chain;
  124. if (son[u]) {
  125. DFS2 (son[u], chain);
  126. }
  127. for (auto v: edge[u]) {
  128. if (v == fa[u] || v == son[u]) continue;
  129. DFS2 (v, v);
  130. }
  131. }
  132.  
  133. void DFS1(int u, int pa) {
  134. sz[u] = 1; dep[u] = dep[pa] + 1;
  135. son[u] = 0; fa[u] = pa;
  136. for (auto v: edge[u]) {
  137. if (v == pa) continue;
  138. DFS1 (v, u);
  139. sz[u] += sz[v];
  140. if (sz[son[u]] < sz[v]) son[u] = v;
  141. }
  142. }
  143.  
  144. void prepare() {
  145. sz[0] = dep[0] = fa[0] = 0;
  146. DFS1 (1, 0);
  147. loc = 0;
  148. DFS2 (1, 1);
  149. W.build (1, n, 1);
  150. L.build (1, n, 1);
  151. }
  152.  
  153. void init_edge(int n) {
  154. for (int i=1; i<=n; ++i) {
  155. edge[i].clear ();
  156. }
  157. }
  158.  
  159. int main() {
  160. int T;
  161. scanf ("%d", &T);
  162. while (T--) {
  163. scanf ("%d", &n);
  164.  
  165. init_edge (n);
  166. for (int i=1; i<n; ++i) {
  167. int u, v;
  168. scanf ("%d%d", &u, &v);
  169. edge[u].push_back (v);
  170. edge[v].push_back (u);
  171. }
  172.  
  173. prepare ();
  174.  
  175. int q;
  176. scanf ("%d", &q);
  177. while (q--) {
  178. int t, u, v;
  179. scanf ("%d%d%d", &t, &u, &v);
  180. if (t == 3) {
  181. printf ("%d\n", query (u, v));
  182. } else {
  183. modify (t, u, v);
  184. }
  185. }
  186. }
  187. return 0;
  188. }

  

树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)的更多相关文章

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  4. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  5. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  6. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  7. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  8. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  10. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

随机推荐

  1. Ubuntu虚拟机中断后重启网络断接错误解决方案

    因为该死的windows自动更新,所以vmplayer经常会被强制关闭. 但重新启动后,会发生不能连接到网络的情况显示: waiting for the network configuration…… ...

  2. 在Azure虚拟机上安装SQL server

    Azure虽然向用户提供SQL paas服务,但是大多数用户还是习惯在用虚拟机自己搭建SQL server,这样的好处是便于后期最大化的扩展,所以鉴于这些情况,所以觉得有必要写这篇博客. 首先,我们要 ...

  3. Appcan——Box

    Box架构 ub….. Box架构元素空间大小分配比例 ub-f……. Ub-f1,ub-f2,ub-f3……. Box架构元素垂直方向的位置排列 ub-ac,ub-ae… -webkit-box-a ...

  4. win10 系统亮度调节

    win10系统发行后,许多用户尝试新的系统发现安装之后亮度无法调节,我也多次遇见此情况 故在此记录修改方式: 打开注册表 -> 搜索键值featuretestcontrol -> 修改键值 ...

  5. web.xml添加编码过滤器

    解决前后台交互汉字乱码 在项目中的web.xml中添加如下代码: <filter> <filter-name>CharacterEncodingFilter</filte ...

  6. django test

    django的单元测试 官方文档:https://docs.djangoproject.com/en/dev/topics/testing/ 相对于自己封装urllib/urllib2/request ...

  7. ORA-00257: archiver error. Connect internal only, until freed.

    早上BA抄送客户的邮件过来,说系统用不了,应用系统报异常Unable to open connection to oracle,Microsoft Provider v2.0.50727.42,既然是 ...

  8. 判断一个字符串str不为空的方法

    1.str == null; 2."".equals(str); 3.str.length 4.str.isEmpty(); 注意:length是属性,一般集合类对象拥有的属性,取 ...

  9. ajaxFileupload多文件上传

    最近有个功能模块需要上传图片,为了和之前的伙伴们保持一致我也使用了ajaxFileupload, 但是源码只支持单文件上传,所以百般斟酌之下决定修改源码,废话不多说直接上代码 HTML上传代码段: & ...

  10. Date、Calender类及日期和字符串转换

    Calendar是一个抽象类,抽象类java.util.Calendar 不可以通过new来获取一个实例,可以通过类方法getinstance()获取此类型的一个通用的对象 ①用法: Calendar ...