ZOJ 3686 A Simple Tree Problem(线段树)

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 = 100010;
  5 
  6 int flip[MAX*4], sum[MAX*4], cnt[MAX*4];//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(1) ;}
 12 
 13 void init() {
 14     ecnt = 1;
 15     dfs_clock = 0;
 16     memset(head, 0, sizeof(head));
 17     memset(flip, 0, sizeof(flip));
 18     memset(cnt, 0, 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] = 1;
 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 * 2, rc = x * 2 + 1;
 36     if(l < r) {
 37         cnt[x] = cnt[rc] + cnt[lc];
 38     }
 39 }
 40 
 41 void pushdown(int x) {
 42     int lc = x * 2, rc = x * 2 + 1;
 43     if(flip[x]) {
 44         flip[x] = 0;
 45         flip[lc] ^= 1;
 46         cnt[lc] = sum[lc] - cnt[lc];
 47         flip[rc] ^= 1;
 48         cnt[rc] = sum[rc] - cnt[rc];
 49     }
 50 }
 51 
 52 void update(int x, int l, int r) {
 53     int lc = x * 2, rc = x * 2 + 1;
 54     if(y1 <= l && r <= y2) {
 55         flip[x] ^= 1;
 56         cnt[x] = sum[x] - cnt[x];
 57     }
 58     else {
 59         pushdown(x);
 60         int mid = (l + r) / 2;
 61         if(y1 <= mid) update(lc, l, mid);
 62         if(mid < y2) update(rc, mid + 1, 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 * 2, rc = x * 2 + 1;
 71     if(y1 <= l && r <= y2) ans += cnt[x];
 72     else {
 73         pushdown(x);
 74         int mid = (l + r) / 2;
 75         if(y1 <= mid) query(lc, l, mid);
 76         if(mid < y2) query(rc, mid + 1, r);
 77     }
 78 }
 79 
 80 void build(int x, int l, int r) {
 81     int lc = x * 2, rc = x * 2 + 1;
 82     if(l == r) {
 83         sum[x] = 1;
 84     }
 85     else {
 86         int mid = (l + r) / 2;
 87         build(lc, l, mid);
 88         build(rc, mid + 1, r);
 89         sum[x] = sum[lc] + sum[rc];
 90     }
 91 }
 92 
 93 int main() {
 94     int n, m, x;
 95     char c[2];
 96     while(scanf("%d%d", &n, &m) != EOF) {
 97         init();
 98         for(int i = 2; i <= n; ++i) {
 99             scanf("%d", &x);
100             add_edge(x, i);
101         }
102         dfs(1);
103         build(1, 1, n);
104         while(m--) {
105             scanf("%s%d", c, &x);
106             y1 = beg[x]; y2 = beg[x] + size[x] - 1;
107             if(c[0] == 'o') {
108                 update(1, 1, n);
109             }
110             if(c[0] == 'q') {
111                 ans = 0;
112                 query(1, 1, n);
113                 printf("%d\n", ans);
114             }
115         }
116         puts("");
117     }
118 }
View Code

 

posted @ 2013-07-29 22:39  Oyking  阅读(286)  评论(0编辑  收藏  举报