题意:一棵树,有很多分叉,每个分叉上最多有1个苹果。

  给出n,接下来n-1行,每行u,v,表示分叉u,v之间有树枝相连。这里数据中u相当于树中的父节点,v相当于子节点。

  给出两个操作:

  1.C x  如果分叉x有一个苹果,表示该苹果被摘下;如果没苹果,表示该分叉长出1个苹果。

  2.Q x  查询以分叉x为根节点的子树中所含有的苹果,包括分叉x。

思路:用树的后根遍历将树转化成一个序列,然后用树状数组维护。

  树的后根遍历(先遍历每棵子树,再遍历根节点)实质上是按照自下而上、从左至右的顺序将非线性结构的树转化为一个线性序列。

  每棵子树对应这个线性序列的一个连续的子区间,这样就可以用树状数组来维护更新。

原本我用vector超时,改用邻接表AC 。

代码一:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector> using namespace std;
const int maxn=;
int n,m,val=,tot=; //val即为树状数组中的顺序编号,tot为邻接表的边序号
int c[maxn]; //树状数组
int a[maxn]; //a[i]表示分叉i的苹果的值,0或1
int hash_value[maxn]; //hash_value[i]表示分叉i在树状数组中的序号
int left_leaf[maxn]; //left_leaf[i]表示以i为根节点的子树中最左底端的叶子节点的编号,该值的hash_value即为以i为根节点的子树在树状数组中的区间的最左端
int head[maxn]; struct Edge {
int to,next;
} edge[maxn]; void add(int u,int v) {
edge[tot].next=head[u];
edge[tot].to=v;
head[u]=tot++;
}
int lowbit(int x) {
return x&(-x);
}
void update(int i,int val) {
while(i<=n) {
c[i]+=val;
i+=lowbit(i);
}
}
int sum(int i) {
int sum=;
while(i) {
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
//dfs后根遍历,求取每个节点在树状数组中的顺序编号,以及每棵子树的left_leaf值
void dfs(int u) {
if(head[u]==-) {
hash_value[u]=++val;
left_leaf[u]=u;
return;
}
int v,flag=;
for(int k=head[u]; k!=-; k=edge[k].next) {
v=edge[k].to;
dfs(v);
if(flag) {
//这里的v即使父节点u的最先访问的子节点
left_leaf[u]=left_leaf[v];
flag=;
}
}
hash_value[u]=++val;
}
int main() {
int u,v;
memset(head,-,sizeof(head));
scanf("%d",&n);
for(int i=; i<n; i++) {
scanf("%d%d",&u,&v);
add(u,v);
}
dfs();
memset(c,,sizeof(c)); for(int i=; i<=n; i++) {
a[i]=;
update(i,);
} scanf("%d",&m);
char str[];
int l,r;
for(int i=; i<m; i++) {
scanf("%s%d",str,&u);
if(str[]=='Q') {
r=hash_value[u];
l=left_leaf[u];
l=hash_value[l];
//[l,r]即为以u为根节点的子树在树状数组中的区间
printf("%d\n",sum(r)-sum(l-));
} else {
r=hash_value[u];
if(a[r]==) {
a[r]=;
update(r,-);
} else {
a[r]=;
update(r,);
}
}
}
return ;
}

也可以用结构体,来存储每个以节点i为根节点的子树在树状数组中的区间左端点和右端点:

代码二:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm> using namespace std;
const int maxn=;
int n,m;
int c[maxn]; //树状数组
bool a[maxn]; //用来标记该节点是否有苹果
int cnt=;
int head[maxn];
int tot=; struct Edge {
int next,to;
} edge[maxn]; struct Apple {
int l,r; //apple[u]的l和r表示以u为根的子树在树状数组中对应区间
} apple[maxn]; void add(int u,int v) {
edge[tot].next=head[u];
edge[tot].to=v;
head[u]=tot++;
}
//dfs,从节点u出发,计算即节点u为根的子树区间[apple[u].l,apple[u].r]
void dfs(int u) {
if(head[u]==-) {
apple[u].l=apple[u].r=cnt;
cnt++;
return;
}
apple[u].l=cnt;
for(int k=head[u]; k!=-; k=edge[k].next) {
int v=edge[k].to;
dfs(v);
}
apple[u].r=cnt++;
}
int lowbit(int x) {
return x&(-x);
}
void update(int i,int v) {
while(i<=cnt) {
c[i]+=v;
i+=lowbit(i);
}
}
int sum(int i) {
int res=;
while(i) {
res+=c[i];
i-=lowbit(i);
}
return res;
}
int main() {
char str[];
int u,v;
memset(head,-,sizeof(head));
memset(a,true,sizeof(a));
scanf("%d",&n);
for(int i=; i<n-; i++) {
scanf("%d%d",&u,&v);
add(u,v);
}
dfs();
scanf("%d",&m);
//初始时,每个节点数都有一个苹果
for(int i=; i<=n; i++)
update(apple[i].r,);
for(int i=; i<=m; i++) {
scanf("%s%d",str,&u);
if(str[]=='C') {
if(a[u]) {
update(apple[u].r,-);
a[u]=false;
} else {
update(apple[u].r,);
a[u]=true;
}
} else {
printf("%d\n",sum(apple[u].r)-sum(apple[u].l-));
}
}
return ;
}

POJ 3321 Apple Tree(后根遍历将树转化成序列,用树状数组维护)的更多相关文章

  1. POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)

    POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...

  2. POJ - 3321 Apple Tree (线段树 + 建树 + 思维转换)

    id=10486" target="_blank" style="color:blue; text-decoration:none">POJ - ...

  3. POJ 3321 Apple Tree 【树状数组+建树】

    题目链接:http://poj.org/problem?id=3321 Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submiss ...

  4. POJ 3321 Apple Tree (DFS + 树状数组)

    题意: 一棵苹果树有N个分叉,编号1---N(根的编号为1),每个分叉只能有一颗苹果或者没有苹果. 现在有两种操作: 1.某个分叉上的苹果从有变无或者从无边有. 2.需要统计以某个分叉为根节点时,它的 ...

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

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10486 题意:一颗有n个分支的苹果树,根为1,每个分支只有一个苹果,给出n- ...

  6. poj 3321:Apple Tree(树状数组,提高题)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Descr ...

  7. POJ 3321 Apple Tree(DFS序+线段树单点修改区间查询)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25904   Accepted: 7682 Descr ...

  8. POJ 3321 Apple Tree dfs+二叉索引树

    题目:http://poj.org/problem?id=3321 动态更新某个元素,并且求和,显然是二叉索引树,但是节点的标号不连续,二叉索引树必须是连续的,所以需要转化成连续的,多叉树的形状已经建 ...

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

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

随机推荐

  1. sicily 1010. 单词数值

    本题主要是Hash思想的应用 课程上机练习题 Contest ends in 8 months 27 days  

  2. 关于Silverlight调用天气预报接口问题

    问题:因Silverlight客户端不能直接调用webservice接口(外网天气接口),调用会出现跨域访问的问题,即使添加了跨域文件也不好使.解决方法如下 解决方法一:1.在服务端建立一个wcf服务 ...

  3. cordova ios

    使用Cordova进行iOS开发 (环境配置及基本用法) 字数1426 阅读3044 评论0 喜欢5 安装Cordova CLI 1. cordova的安装: 1.1 安装cordova需要先安装no ...

  4. EF-Code First 入门

    本文程序基于VS2015.EF6.1,本文不做过多深入讨论,只是个入门. EF 就是微软的 EntityFramework,主要分为 DB First,Model First,Code First.之 ...

  5. oracle数据库一些问题

    1.oracle12安装的过程中需要注意字符的选择(特别注意 选择ZHS16GBK 国内企业大多选这个   否则创建数据的时候会出现中文变成问号) 2.设置密码是必须是大小写混合的 pl/sql32链 ...

  6. 存储映射IO

    mmap 将文件映射到内存, 对这块内存的修改会自动同步到相应的文件中 void *mmap(void *addr, size_t len, int prot, int flag, int fd, o ...

  7. ActiveMQ之Topic

    与Queue不同,Topic实现的是发布/订阅模型,在下面的例子中,启动两个消费者共同监听一个Topic,然后循环给这个Topic发送多个消息. 例子: public class TopicTest ...

  8. Oracle定义两个变量,并对两个变量的值的长度进行判断

    这个例子其实很简单,但是往往简单的东西如果不用心就会漏洞百出,简单的一个逻辑判断,是为了给复杂逻辑判断做出铺垫 语法格式: if<condition_expression> then pl ...

  9. Java中的继承和多态

    1.  什么是继承,继承的特点? 子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类更具体.父类具有更 ...

  10. Scrumworks乱码

    要搞敏捷,先找个工具.选了scrumworks5.1.安装完后发现录入汉字乱码. 环境: server:CentOS linux db:mysql5.0 appserver:jboss(scrumwo ...