poj 3321 Apple Tree

题意:

有一棵树,这棵树上有很多果子,一开始每个果子都在,给出下面两种操作:

1.C x,改变果子x的状态,如果有,那么久摘下来;没有,就变为有;

2.Q x,问在x上面的(包括x)有多少个果子。

思路:

多叉树,朴素的更新方法就是从叶子到根的路径上的点的值全部更新,但是这样每更新的复杂度是O(n)。

所以就要考虑如何较快地更新。

树状数组的更新是logn,那么就要考虑如何把树上的问题转换为区间的问题,这就用到了dfs序。

“一棵子树的dfs序就变成了一个区间”

通过记录dfs序,那么一个节点及其子节点就构成了一段连续的区间,所以就可以用树状数组进行信息的维护。

对于这道题来说,对于每一个节点,记录两个信息,一个是第一次访问到它的时间l,第二个是它的子节点中最大的访问时间r,那么从l到r这一段连续的数字就是这个节点及其所有子节点的区间。

更新x,就是将l[x] ~ n这一段区间更新;

查询x上面的数字之和,就是查询1 ~ r[x] 与 1 ~ l[x]-1的差值。

这两个操作就是树状数组的基本功能,单点更新与区间查询。

注意建树不能用vector,得用链式前向星。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 using namespace std;
  5 const int N = 2e5 + 10;
  6 struct edge
  7 {
  8     int to,next;
  9 } edges[N];
 10 int head[N];
 11 int l[N],r[N];
 12 int c[N];
 13 bool vis[N];
 14 int tot = 0,n;
 15 int cnt;
 16 void adde(int u,int v)
 17 {
 18     edges[++cnt].to = v;
 19     edges[cnt].next = head[u];
 20     head[u] = cnt;
 21 }
 22 void dfs(int u,int fa)
 23 {
 24     l[u] = ++tot;
 25     for (int i = head[u];i;i = edges[i].next)
 26     {
 27         int v = edges[i].to;
 28         if (v != fa)
 29         {
 30             dfs(v,u);
 31         }
 32     }
 33     r[u] = tot;
 34 }
 35 int lowbit(int x)
 36 {
 37     return x&(-x);
 38 }
 39 void add(int x,int y)
 40 {
 41     for (int i = x;i <= n;i += lowbit(i)) c[i] += y;
 42 }
 43 int getsum(int x)
 44 {
 45     int ans = 0;
 46     for (int i = x;i > 0;i -= lowbit(i)) ans += c[i];
 47     return ans;
 48 }
 49 int main()
 50 {
 51     int m;
 52     while (scanf("%d",&n) != EOF)
 53     {
 54         tot = 0;
 55         cnt = 0;
 56         memset(l,0,sizeof(l));
 57         memset(r,0,sizeof(r));
 58         memset(c,0,sizeof(c));
 59         memset(head,0,sizeof(head));
 60         for (int i = 1;i <= n;i++)
 61         {
 62             vis[i] = 1;
 63         }
 64         //for (int i = 1;i <= n;i++) g[i].clear();
 65         for (int i = 0;i < n - 1;i++)
 66         {
 67             int u,v;
 68             scanf("%d%d",&u,&v);
 69             adde(u,v);
 70             adde(v,u);
 71         }
 72         dfs(1,-1);
 73         //printf("%d %d\n",l[3],r[3]);
 74         for (int i = 1;i <= n;i++) add(i,1);
 75         scanf("%d",&m);
 76         for (int i = 0;i < m;i++)
 77         {
 78             char s[5];
 79             scanf("%s",s);
 80             if (s[0] == 'Q')
 81             {
 82                 int x;
 83                 scanf("%d",&x);
 84                 int mx = getsum(r[x]);
 85                 int mi = getsum(l[x] - 1);
 86                 //printf("%d %d**\n",r[x],l[x]);
 87                 printf("%d\n",mx - mi);
 88             }
 89             else
 90             {
 91                 int x;
 92                 scanf("%d",&x);
 93                 if (vis[x])
 94                 {
 95                     vis[x] = 0;
 96                     add(l[x],-1);
 97                 }
 98                 else
 99                 {
100                     vis[x] = 1;
101                     add(l[x],1);
102                 }
103             }
104         }
105     }
106     return 0;
107 }

 

posted @ 2018-05-23 16:01  qrfkickit  阅读(214)  评论(0编辑  收藏  举报