题意:一棵苹果树有n个结点,编号从1到n,根结点永远是1。该树有n-1条树枝,每条树枝连接两个结点。已知苹果只会结在树的结点处,而且每个结点最多只能结1个苹果。初始时每个结点处都有1个苹果。树的主人接下来会进行m个操作。操作共两种。C X表示将结点x上的苹果数量改变,原本是1,则现在为0,原本是0,现在是1。Q X表示一次查询。要求输出结点X和其子树上的苹果总数。n和m最大可到100000。

操作只有更新和查询两种,树状数组最合适了。

首先是树状数组的相关知识。网上有很多讲解,在这里传送一个讲解的地址 传送门

树状数组最重要的就是要搞明白那种经典的图,之后就没什么问题了。

思路:本题的关键是如何将树映射成线性的数组。而且树状数组一般是对连续区间求和,又依照题意的要求,树的子树要在区间内也是连续存储的。这里的方法是,采用dfs对树进行一次遍历,树的每一个结点都有st和ed两个时间戳,分别记录该结点被遍历到的时间戳以及它和它的子树全部遍历完后的时间戳。举一个例子来说明。

依次遍历到的结点:1  5  4  3  2

对应的时间戳:1  2  3  4  5

拿结点4来说,它的开始时间戳st为3,结束时间戳ed为5。

这样的话,假如需要询问结点x和它子树上的苹果总数,只需对区间[st[x], ed[x]]求和即可。另外需要注意的是,树状数组求和函数query求的是区间[1, x]的和,因此要实现之前的求和,需要用query(ed[x]) - query(st[x] - 1)。 (query(0) = 0)

以上就是解题思路了。

此外要注意,在建图的时候,添加边应该是双向边(即无向边),不然在遍历时会出现遍历不到或者其他问题。一开始我提交了两次总是tle,问题就在这里。

至于树状数组更新的时候,假设更新位置为x,则应将后续的x += lowbit[x]的位置也更新,直到x大于n。做这题时,我以为只要更新到结点x的结束位置ed[x]即可,但基于树状数组的特点,x变化后,后续结点即使不在x的子树里也是有可能受影响的,应当更新。不然在求和时就会得出错误结果。

 #include<stdio.h>
#include<string.h>
#define maxn 100020
#define maxp 200020
struct node
{
int v;
int next;
}edge[maxp];
int num_edge, head[maxn];
void addedge(int a, int b)
{
edge[num_edge].v = b;
edge[num_edge].next = head[a];
head[a] = num_edge++;
}
void init_edge()
{
num_edge=;
memset(head,-,sizeof(head));
} int st[maxn], ed[maxn], vis[maxn], cnt;//cnt记录时间戳,初始为0
void get_timestamp(int u)
{
vis[u] = ;
st[u] = ++cnt;//记录开始时间戳
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].v;
if (!vis[v]) get_timestamp(v);
}
ed[u] = cnt;//记录结束时间戳
} int lowbit[maxn], apple[maxn];
int n;//fork的总数
void update(int x,int num)
{
for (int i = x; i <= n; i += lowbit[i])
apple[i] += num;
}
int query(int x)
{
int res = ;
for (int i = x; i > ; i -= lowbit[i])
res += apple[i];
return res;
}
int main()
{
//freopen("data.in", "r", stdin);
scanf("%d",&n);
init_edge();
for (int i = ; i < n; i++)
{
int u, v;
scanf("%d%d",&u,&v);
addedge(u, v);
addedge(v, u);
}
cnt = ;
memset(vis, , sizeof(vis));
get_timestamp();
for (int i = ; i <= n; i++)
lowbit[i] = i & (i ^ (i - ));
for (int i = ; i <= n; i++)
update(i, );
int m;
scanf("%d",&m);
while (m--)
{
char op;
int x;
getchar();
scanf("%c %d",&op,&x);
if (op == 'Q')
printf("%d\n",query(ed[x]) - query(st[x] - ));
else
{
if (query(st[x]) - query(st[x] - ) == )
update(st[x], -);
else update(st[x], );
}
}
return ;
}

POJ 3321 Apple Tree 树状数组+DFS的更多相关文章

  1. POJ 3321 Apple Tree (树状数组+dfs序)

    题目链接:http://poj.org/problem?id=3321 给你n个点,n-1条边,1为根节点.给你m条操作,C操作是将x点变反(1变0,0变1),Q操作是询问x节点以及它子树的值之和.初 ...

  2. POJ 3321 Apple Tree(树状数组)

                                                              Apple Tree Time Limit: 2000MS   Memory Lim ...

  3. POJ 3321 Apple Tree 树状数组 第一题

    第一次做树状数组,这个东西还是蛮神奇的,通过一个简单的C数组就可以表示出整个序列的值,并且可以用logN的复杂度进行改值与求和. 这道题目我根本不知道怎么和树状数组扯上的关系,刚开始我想直接按图来遍历 ...

  4. POJ--3321 Apple Tree(树状数组+dfs(序列))

    Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22613 Accepted: 6875 Descripti ...

  5. E - Apple Tree(树状数组+DFS序)

    There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. ...

  6. 3321 Apple Tree 树状数组

    LIANJIE:http://poj.org/problem?id=3321 给你一个多叉树,每个叉和叶子节点有一颗苹果.然后给你两个操作,一个是给你C清除某节点上的苹果或者添加(此节点上有苹果则清除 ...

  7. POJ 3321:Apple Tree 树状数组

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 22131   Accepted: 6715 Descr ...

  8. POJ3321 Apple Tree(树状数组)

    先做一次dfs求得每个节点为根的子树在树状数组中编号的起始值和结束值,再树状数组做区间查询 与单点更新. #include<cstdio> #include<iostream> ...

  9. POJ 2486 Apple Tree [树状DP]

    题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1.一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果. 思路:这里给出数组的定义: dp[0][x][j] 为从结点 ...

随机推荐

  1. git使用问题整理

    git访问远端仓库报"fatal: Authentication failed for"错误的,可能原因是账户密码变更,git配置了使用creditial helper,所以需要取 ...

  2. uoj206 [APIO2016]最大差分

    ref #include "gap.h" #include <iostream> #include <cstdio> using namespace std ...

  3. 59、佳博wifi打印机怎么配置

    1.去这里下载配置软件(注意,需要再windows下进行)http://pan.baidu.com/s/1bn1y4FX,并解压安装程序 2.连上wifi打印机的热点,比如说佳博打印机的默认为Gpri ...

  4. IOS开发学习笔记019-动态创建控件

    动态创建控件 一.按钮 二.文本输入框 三.lable标签 注意: 只是简单的拖拽控件会毁了你,所以最好还是手动通过代码创建控件. 如果要通过代码生成按钮的话,可以在系统自带的函数viewDidLoa ...

  5. application.properties 详解

    mvc spring.mvc.async.request-timeout设定async请求的超时时间,以毫秒为单位,如果没有设置的话,以具体实现的超时时间为准,比如tomcat的servlet3的话是 ...

  6. C#从大图中截取一部分图片

    #region 从大图中截取一部分图片 /// <summary> /// 从大图中截取一部分图片 /// </summary> /// <param name=&quo ...

  7. get_class 方法

    get_class 返回对象的类名 get_class (PHP 4, PHP 5) get_class — 返回对象的类名 说明 string get_class ([ object $obj ] ...

  8. 第二篇:python基础_2

    本篇内容 数字 字符串 元祖 字典 列表 集合 for循环 二进制 字符编码 文件处理 一.数字 1.int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2 ...

  9. 【bzoj3884】上帝与集合的正确用法 扩展欧拉定理

    题目描述 根据一些书上的记载,上帝的一次失败的创世经历是这样的: 第一天, 上帝创造了一个世界的基本元素,称做“元”. 第二天, 上帝创造了一个新的元素,称作“α”.“α”被定义为“元”构成的集合.容 ...

  10. python请求带cookie

    先获得cookie到文件 import cookielib import urllib2 #设置保存cookie的文件,同级目录下的cookie.txt filename = 'cookie.txt' ...