zoukankan      html  css  js  c++  java
  • 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
    ",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**
    ",r[x],l[x]);
     87                 printf("%d
    ",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 }
  • 相关阅读:
    C# 设计模式(3)工厂方法模式
    C# 设计模式(2)简单工厂模式
    C# .Net Core读取AppSettings
    C# 设计模式(1)单例模式
    C# MarshalByRefObject
    使用64位TestStand调用32位LabVIEW代码模块
    LIN 总线入门
    C#版本与.NET版本对应关系以及各版本的特性
    数字货币提醒小工具
    C#根据描述获取枚举
  • 原文地址:https://www.cnblogs.com/kickit/p/9077354.html
Copyright © 2011-2022 走看看