POJ 3321 Apple Tree 树状数组+DFS
题意:一棵苹果树有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的更多相关文章
- POJ 3321 Apple Tree (树状数组+dfs序)
题目链接:http://poj.org/problem?id=3321 给你n个点,n-1条边,1为根节点.给你m条操作,C操作是将x点变反(1变0,0变1),Q操作是询问x节点以及它子树的值之和.初 ...
- POJ 3321 Apple Tree(树状数组)
Apple Tree Time Limit: 2000MS Memory Lim ...
- POJ 3321 Apple Tree 树状数组 第一题
第一次做树状数组,这个东西还是蛮神奇的,通过一个简单的C数组就可以表示出整个序列的值,并且可以用logN的复杂度进行改值与求和. 这道题目我根本不知道怎么和树状数组扯上的关系,刚开始我想直接按图来遍历 ...
- POJ--3321 Apple Tree(树状数组+dfs(序列))
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22613 Accepted: 6875 Descripti ...
- 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. ...
- 3321 Apple Tree 树状数组
LIANJIE:http://poj.org/problem?id=3321 给你一个多叉树,每个叉和叶子节点有一颗苹果.然后给你两个操作,一个是给你C清除某节点上的苹果或者添加(此节点上有苹果则清除 ...
- POJ 3321:Apple Tree 树状数组
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22131 Accepted: 6715 Descr ...
- POJ3321 Apple Tree(树状数组)
先做一次dfs求得每个节点为根的子树在树状数组中编号的起始值和结束值,再树状数组做区间查询 与单点更新. #include<cstdio> #include<iostream> ...
- POJ 2486 Apple Tree [树状DP]
题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1.一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果. 思路:这里给出数组的定义: dp[0][x][j] 为从结点 ...
随机推荐
- spark的flatMap和map区别
map()是将函数用于RDD中的每个元素,将返回值构成新的RDD. flatmap()是将函数应用于RDD中的每个元素,将返回的迭代器的所有内容构成新的RDD,这样就得到了一个由各列表中的元素组成的R ...
- git使用问题整理
git访问远端仓库报"fatal: Authentication failed for"错误的,可能原因是账户密码变更,git配置了使用creditial helper,所以需要取 ...
- IOS开发学习笔记006 - 指针
C语言 指针 简单使用如下: int *p;//定义 int a = 10; p = &a;//赋值 int * b = &a;//定义并赋值 定义格式:类型 *指针变量名: 注意事项 ...
- ROM+VGA 图片显示
内容 1.将一幅图片制成mif文件,初始化rom,图片像素为 120 * 60 2.驱动VGA,将图片显示在屏幕上 1.VGA 时序 下面是我的笔记截图,感觉更好理解. 2.640*480 60hz ...
- [oldboy-django][2深入django]Form组件实现生成: select下拉框, checkbox复选框,radio单选框以及如何实现自定义数据格式要求
1 需求 - 1Form组件如何实现生成选择类标签: select,check, radio - 默认值 - 保留上次输入的值 - 2自定义验证规则 - RegexField - -
- [译]tar打包时忽略某些文件夹内容
使用tar的 --exclude的选项 $ tar --exclude='./folder' --exclude='./upload/folder2' -zcvf /backup/filename.t ...
- unity c# 代码示例
1. using UnityEngine; using System.Collections; public class AnimatorMove : MonoBehaviour { public f ...
- 构建乘积数组--java
题目:给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1].不能使 ...
- bzoj3680吊打GTY
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=3680 sol :吊打出题人(逃~ puts("nan") 出题人题解:h ...
- leetcode 21 list merge
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...