POJ 3321 Apple Tree

题目大意:

        一颗苹果树上共有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, 洋芋,培植

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值