Description

Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0.

We define this kind of operation: given a subtree, negate all its labels.

And we want to query the numbers of 1's of a subtree.

Input

Multiple test cases.

First line, two integer N and M, denoting the numbers of nodes and numbers of operations and queries.(1<=N<=100000, 1<=M<=10000)

Then a line with N-1 integers, denoting the parent of node 2..N. Root is node 1.

Then M lines, each line are in the format "o node" or "q node", denoting we want to operate or query on the subtree with root of a certain node.

Output

For each query, output an integer in a line.

Output a blank line after each test case.

题目大意:给一棵多叉树,初始值都为0,o x为翻转以x为根的子树,q x为查询以x为根的子树有多少个1

思路:这数据范围,暴力是不行的,怎么暴力都是不行的>_<。这题的要求是:修改一大片、查询一大片,比较容易想到的就是线段树(树状数组也可以,不过要翻转嘛……好像有难度……反正我不会>_<)。问题是这玩意儿怎么转换成线段树呢?要转化成线段树,就要把每个点的子孙们都放到一片连续的空间里。这时,若使用DFS,遍历的顺序刚刚好符合要求,于是我们就DFSo(∩_∩)o 。DFS途中就可以算出每个点的及其子孙覆盖的区域。然后变成线段树之后呢,随便搞搞就行了o(∩_∩)o

  1. #include <cstdio>
  2. #include <cstring>
  3.  
  4. const int MAX = ;
  5.  
  6. int flip[MAX*], sum[MAX*], cnt[MAX*];//tree
  7. int head[MAX], next[MAX], to[MAX], ecnt;
  8. int beg[MAX], size[MAX], dfs_clock;
  9. int y1, y2;
  10.  
  11. void tle() {while() ;}
  12.  
  13. void init() {
  14. ecnt = ;
  15. dfs_clock = ;
  16. memset(head, , sizeof(head));
  17. memset(flip, , sizeof(flip));
  18. memset(cnt, , sizeof(cnt));
  19. }
  20.  
  21. void add_edge(int u, int v) {
  22. to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
  23. }
  24.  
  25. void dfs(int x) {
  26. size[x] = ;
  27. beg[x] = ++dfs_clock;
  28. for(int p = head[x]; p; p = next[p]) {
  29. dfs(to[p]);
  30. size[x] += size[to[p]];
  31. }
  32. }
  33.  
  34. void maintain(int x, int l, int r) {
  35. int lc = x * , rc = x * + ;
  36. if(l < r) {
  37. cnt[x] = cnt[rc] + cnt[lc];
  38. }
  39. }
  40.  
  41. void pushdown(int x) {
  42. int lc = x * , rc = x * + ;
  43. if(flip[x]) {
  44. flip[x] = ;
  45. flip[lc] ^= ;
  46. cnt[lc] = sum[lc] - cnt[lc];
  47. flip[rc] ^= ;
  48. cnt[rc] = sum[rc] - cnt[rc];
  49. }
  50. }
  51.  
  52. void update(int x, int l, int r) {
  53. int lc = x * , rc = x * + ;
  54. if(y1 <= l && r <= y2) {
  55. flip[x] ^= ;
  56. cnt[x] = sum[x] - cnt[x];
  57. }
  58. else {
  59. pushdown(x);
  60. int mid = (l + r) / ;
  61. if(y1 <= mid) update(lc, l, mid);
  62. if(mid < y2) update(rc, mid + , r);
  63. maintain(x, l, r);
  64. }
  65. }
  66.  
  67. int ans;
  68.  
  69. void query(int x, int l, int r) {
  70. int lc = x * , rc = x * + ;
  71. if(y1 <= l && r <= y2) ans += cnt[x];
  72. else {
  73. pushdown(x);
  74. int mid = (l + r) / ;
  75. if(y1 <= mid) query(lc, l, mid);
  76. if(mid < y2) query(rc, mid + , r);
  77. }
  78. }
  79.  
  80. void build(int x, int l, int r) {
  81. int lc = x * , rc = x * + ;
  82. if(l == r) {
  83. sum[x] = ;
  84. }
  85. else {
  86. int mid = (l + r) / ;
  87. build(lc, l, mid);
  88. build(rc, mid + , r);
  89. sum[x] = sum[lc] + sum[rc];
  90. }
  91. }
  92.  
  93. int main() {
  94. int n, m, x;
  95. char c[];
  96. while(scanf("%d%d", &n, &m) != EOF) {
  97. init();
  98. for(int i = ; i <= n; ++i) {
  99. scanf("%d", &x);
  100. add_edge(x, i);
  101. }
  102. dfs();
  103. build(, , n);
  104. while(m--) {
  105. scanf("%s%d", c, &x);
  106. y1 = beg[x]; y2 = beg[x] + size[x] - ;
  107. if(c[] == 'o') {
  108. update(, , n);
  109. }
  110. if(c[] == 'q') {
  111. ans = ;
  112. query(, , n);
  113. printf("%d\n", ans);
  114. }
  115. }
  116. puts("");
  117. }
  118. }

ZOJ 3686 A Simple Tree Problem(线段树)的更多相关文章

  1. ZOJ 3686 A Simple Tree Problem

    A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each no ...

  2. zoj 3686 A Simple Tree Problem (线段树)

    Solution: 根据树的遍历道的时间给树的节点编号,记录下进入节点和退出节点的时间.这个时间区间覆盖了这个节点的所有子树,可以当做连续的区间利用线段树进行操作. /* 线段树 */ #pragma ...

  3. ZOJ-3686 A Simple Tree Problem 线段树

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686 题意:给定一颗有根树,每个节点有0和1两种值.有两种操作: ...

  4. bzoj 3489 A simple rmq problem - 线段树

    Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直 ...

  5. hdu 4973 A simple simulation problem. (线段树)

    题目链接 题意: 给定n长的序列 m个操作 序列默认为 1, 2, 3···n 操作1:D [l,r] 把[l,r]区间增长 :( 1,2,3,4 进行 D [1,3]变成 1,1,2,2,3,3,4 ...

  6. BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

    A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...

  7. 【BZOJ4999】This Problem Is Too Simple!(线段树)

    [BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...

  8. xtu数据结构 I. A Simple Tree Problem

    I. A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB 64-bit integer IO format: %lld     ...

  9. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

随机推荐

  1. 常见web漏洞

    常见的web漏洞——文件上传漏洞 一.文件上传漏洞概述    文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力.这种攻击方式是最为直接和有效的,有时候几乎没 ...

  2. Linux中文件I/O函数

    一.lseek函数 每个打开文件都有一个与其相关联的“当前文件偏移量”.它通常是一个非负整数,用以度量从文件开始处 计算的字节数.通常,读.写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数 ...

  3. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  4. MySQL 5.7增强半同步测试

            we've know the machenism of semi-synchronous replication in my previous article,let's do som ...

  5. MySQL正则表达式的问题

    原本以为 正则表达式里面的特殊\d匹配数字放到sql语句里面也是适用的,没想到一直不匹配.但是放到编程语言java或者js里面又匹配.看了一下原来sql对正则的支持没有那么全面.一定要用[0-9]代表 ...

  6. Python-调用系统指令小记

    import subprocess def exec_command(cmd, log_path, **kwargs): with open(log_path, 'w') as f: p = subp ...

  7. Flask之蓝图的使用

    蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...

  8. html 的radio单选框如何实现互斥------radio只是input的type属性

    先看看没有互斥的情况: <html> <body> 男性:<input type="radio" id="male" /> ...

  9. 最小化的测试套件minimal_test的使用

    1:需要包含文件文#include <boost/test/minimal_test.hpp> 2:minimal_test内部实现了main(), 因此无需自己编写main()函数, 只 ...

  10. Random类与Random方法

    class Test{ public static void main(String[] args){ int min=2; //定义随机数的最小值 int max=102; //定义随机数的最大值 ...