题意:一棵树,有很多分叉,每个分叉上最多有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. 【风马一族_git_github】git与github的英文记录

    Pull requests  Issues Gist 请求 问题 要点 ---------------------------------------------------------------- ...

  2. activiti搭建(二)与Spring集成

    转载请注明源地址:http://www.cnblogs.com/lighten/p/5876773.html 本文主要讲解如何将Activiti和Spring框架集成,再过一段时间将会将一个基础的de ...

  3. ISE 中使用system generate

    本文讲解简单的ISE中使用system generate,system generate基本使用规则在此不详细说明可以见博客http://blog.csdn.net/xiabodan/article/ ...

  4. 创建本地Ubuntu镜像

    参考文档 http://www.howtoforge.com/local_debian_ubuntu_mirror 安装服务 : sudo apt-get install apt-mirror apa ...

  5. shell脚本初识

    #!/bin/bash(linux脚本环境的声明即解释器,该解释器为bash,位于根目录下的bin目录下) 变量的定义与赋值: 格式:变量名=变量值(无需声明变量类型) 变量的引用: 格式:$变量名 ...

  6. 模拟抛硬币(C语言实现)

    实现代码: #include<stdio.h> #include<stdlib.h> int heads() { ; } int main(int argc, char *ar ...

  7. Less 导入命令 @import

    在这个less文件上想导入另一个less文件, 连在同级的文件里直接可用文件名 @import url('css.less')或@import rul(css) 连下级的文件 @import url( ...

  8. 延迟加载图片的 jQuery 插件:Lazy Load

    网站的速度非常重要,现在有很多网站优化的工具,如 Google 的Page Speed,Yahoo 的 YSlow,对于网页图片,Yahoo 还提供 Smush.it这个工具对图片进行批量压缩,但是对 ...

  9. js设计模式(4)---组合模式

    0.前言 今天是建党节,新疆那边又开始了闹腾.作为立志成为码农的我,现在已经从一个大愤青淡化为一个小愤青,对这些国家民生大事不在血气喷发,转而把经历发泄在技术问题上面,因而在扯一篇随笔吧,把无处发泄的 ...

  10. Linux之父访谈录:设计内核只为了好玩

    2010-09-20 10:36 “有 些人生来就具有统率百万人的领袖风范;另一些人则是为写出颠覆世界的软件而生.唯一一个能同时做到这两 者的人,就是Linus Torvalds.”这是美国<时 ...