题目大意:
一颗苹果树上共有N个分叉点(最后的尖头也算分叉点,N ≤ 100,000)编号为1 ~ N,初始时每个分叉点都有一颗苹果,现只有一个测例,会给出树的结构,即给出N - 1一条边,每条边的形式为"u v",表示u是v的父结点,接下来将有M此询问(M ≤ 100,000),询问共有两种,一种是"C x"表示将编号为x的结点的状态改变,即有苹果变成没苹果,没苹果变成有苹果(每个分叉点最多有一个苹果或没有苹果),另一种询问是"Q x",表示要求输出以编号为x的分叉点为子树(包括x)上所有苹果的数量。
注释代码:
/*
* Problem ID : POJ 3321 Apple Tree
* Author : Lirx.t.Una
* Language : C
* Run Time : 438 ms
* Run Memory : 5336 KB
*/
#include <memory.h>
#include <stdio.h>
//分叉的最大数量
#define MAXN 100000
//思路:为了使用树状数组则必须将一颗子树所在的范围
//构造成一个封闭连续的区间,根据深度优先遍历的原理,
//当遍历一颗树的时候是先遍历其所有子树再遍历树根
//因此可以在刚开始遍历时记下根的访问编号,待所有子树
//都遍历完回到根时再记下根的第二次访问编号,这样整棵子树
//都包含在第一次访问根和第二次访问根之间了,因此也就能构造出
//一段连续的区间包住整棵子树了,只不过这样做每个点都会访问两次
//因此最后的结果除以2就是最终答案了
int c[2 * MAXN + 1];//树状数组,记录区间中苹果的总数量
int lowbit[2 * MAXN + 1];//对lowbit打表
//travel number of start and end of a point
//dfs时一个点开始遍历和结束遍历的编号,从1开始计
int sta[MAXN + 1];
int end[MAXN + 1];
int cnt;//遍历编号
//树的邻接表
int head[MAXN + 1];
int nxt[MAXN];
int arc[MAXN];
int e = 1;
//exist,表示某个分叉点是否有苹果
//1表示有苹果,-1表示没有苹果
char exi[MAXN + 1];
void
addarc( int u, int v ) {
arc[e] = v;
nxt[e] = head[u];
head[u] = e++;
}
void
dfs_build(int u) {//构造遍历编号为构造树状数组做准备
int i;
sta[u] = ++cnt;
for ( i = head[u]; i; i = nxt[i] )
dfs_build( arc[i] );
end[u] = ++cnt;
}
int
query(int i) {
int sum;
sum = 0;
while ( i > 0 ) {
sum += c[i];
i -= lowbit[i];
}
return sum;
}
void
update( int i, int v ) {
while ( i <= cnt ) {
c[i] += v;
i += lowbit[i];
}
}
int
main() {
int n, q;//分叉点数和查询数
int u, v;//临时存放父结点和子结点的编号
char cmd;
int i;//技术变量
scanf("%d", &n);
n--;//总共有n - 1条边
while ( n-- ) {
scanf("%d%d", &u, &v);
addarc( u, v );
}
dfs_build(1);//从根1号结点开始dfs
memset(exi, 1, sizeof(exi));//初始时每个分叉点都有苹果
for ( i = 1; i <= cnt; i++ ) {
lowbit[i] = i & -i;
//公式c[i] = sum[i] - sum[ i - lowbit[i] ]
//而开始时每个结点就只有一个苹果,因此sum[x] = x
//所以c[i] = i - ( i - lowbit[i] ) = lowbit[i]
c[i] = lowbit[i];
}
scanf("%d", &q);
while ( q-- ) {
scanf("\n%c%d", &cmd, &i);
switch (cmd) {
case 'C' :
update( sta[i], -exi[i] );
update( end[i], -exi[i] );
exi[i] = -exi[i];//状态相反
break;
case 'Q' :
//注意要除以2
printf("%d\n", ( query( end[i] ) - query( sta[i] - 1 ) ) >> 1);
break;
default : break;
}
}
return 0;
}
无注释代码:
#include <memory.h>
#include <stdio.h>
#define MAXN 100000
int c[2 * MAXN + 1];
int lowbit[2 * MAXN + 1];
int sta[MAXN + 1];
int end[MAXN + 1];
int cnt;
int head[MAXN + 1];
int nxt[MAXN];
int arc[MAXN];
int e = 1;
char exi[MAXN + 1];
void
addarc( int u, int v ) {
arc[e] = v;
nxt[e] = head[u];
head[u] = e++;
}
void
dfs_build(int u) {
int i;
sta[u] = ++cnt;
for ( i = head[u]; i; i = nxt[i] )
dfs_build( arc[i] );
end[u] = ++cnt;
}
int
query(int i) {
int sum;
sum = 0;
while ( i > 0 ) {
sum += c[i];
i -= lowbit[i];
}
return sum;
}
void
update( int i, int v ) {
while ( i <= cnt ) {
c[i] += v;
i += lowbit[i];
}
}
int
main() {
int n, q;
int u, v;
char cmd;
int i;
scanf("%d", &n);
n--;
while ( n-- ) {
scanf("%d%d", &u, &v);
addarc( u, v );
}
dfs_build(1);
memset(exi, 1, sizeof(exi));
for ( i = 1; i <= cnt; i++ ) {
lowbit[i] = i & -i;
c[i] = lowbit[i];
}
scanf("%d", &q);
while ( q-- ) {
scanf("\n%c%d", &cmd, &i);
switch (cmd) {
case 'C' :
update( sta[i], -exi[i] );
update( end[i], -exi[i] );
exi[i] = -exi[i];
break;
case 'Q' :
printf("%d\n", ( query( end[i] ) - query( sta[i] - 1 ) ) >> 1);
break;
default : break;
}
}
return 0;
}
单词解释:
inquiry:vt, 探究,询问
fork:n, 餐叉,树的分叉点
nurture:vt, 洋芋,培植