题意:一棵树,有很多分叉,每个分叉上最多有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. CXF和Axis的比较【转】

    在SOA领域,我们认为Web Service是SOA体系的构建单元(building block).对于服务开发人员来说,AXIS和CXF一定都不会陌生.这两个产品都是Apache孵化器下面的Web ...

  2. arcgis直连oracle

    参数:service :sde:oracle10g(客户端的数据库版本)username:sdepassword:sde@s19(配置的网络连接名) 黄色背景为需要根据实际情况更改的参数内容.如更改为 ...

  3. Android下各个按键对应的key code

    KEYCODE_UNKNOWN=0; KEYCODE_SOFT_LEFT=1; KEYCODE_SOFT_RIGHT=2; KEYCODE_HOME=3; KEYCODE_BACK=4; KEYCOD ...

  4. ADO.NET笔记——带参数的查询防止SQL注入攻击

    相关知识: 把单引号替换成两个单引号,虽然能起到一定的防止SQL注入攻击的作用,但是更为有效的办法是把要拼接的内容做成“参数” SQLCommand支持带参数的查询,也就是说,可以在查询语句中指定参数 ...

  5. Git错误non-fast-forward后的冲突解决(转载)

    文章转载自:http://blog.csdn.net/chain2012/article/details/7476493 当要push代码到git时,出现提示: error:failed to pus ...

  6. 汇编语言-求X的阶乘

    1. 题目:求X的阶乘值 2. 要求:输入一个整型数(不超过10),求出其阶乘值后输出,求阶乘的算法用子程序来实现. 3. 提示:可以用递归来实现,也可以用简单的循环来实现. 这里使用循环来实现: 对 ...

  7. mysql命令语句来去除掉字段中空格字符的方法

    mysql有什么办法批量去掉某个字段字符中的空格?不仅是字符串前后的空格,还包含字符串中间的空格,答案是 replace,使用mysql自带的 replace 函数,另外还有个 trim 函数.   ...

  8. 通过FTP将一个数据文件从A服务器下载到B服务器的整个过程

    现在的环境如下: 服务器A :192.168.1.104 服务器B:192.168.1.138 需要将A服务器上的某个数据文件下载到B服务器上,传输方式为:FTP 那么,要怎么去实现呢? 首先,需要添 ...

  9. WPF-控件-将ListBox条目水平排列

    <Grid Margin="6"> <ListBox> <!--ItemsPanel--> <ListBox.ItemsPanel> ...

  10. mdelay,udelay,msleep区别

    delay函数是忙则等待,占用CPU时间:而sleep函数使调用的进程进行休眠. udelay引用头文件/include/asm-***/delay.h,mdelay和ndelay则引用/includ ...