您的位置:首页 > 移动开发

poj 3321 Apple Tree( 树状数组 )

2011-06-25 22:49 399 查看
题意 : 有一颗N(N<=10^5)叉的苹果树,每个叉处长有一个苹果。
对该果树有两种操作:
'C x' : 更新果树,若x叉处有苹果,则摘下;若没有,则长出一个新的。
'Q x' : 统计子树x上的苹果数量(包括x)

这题的关键就是怎样将树中的节点映射到树状数组。
解决 : 找到树节点的偏序关系。 
这是我第一道树状数组,感觉树状数组中的元素一定要满足偏序关系,找到偏序关系是应用树状数组的关键,呵呵,不知道这个感觉是否正确,以后遇到了再总结。

Problem: 3321  User: 090609103
Memory: 7212K  Time: 1000MS
Language: C++  Result: Accepted

Source Code
#include <iostream>
using namespace std;

const int Max = 100000;

// 对象
struct Edge {
int id; // 终点号
Edge* next;
Edge( const int id ) {
this->id = id;
next = NULL;
}
};
struct Node {
Edge *first, *last;
int low, high;
bool is_picked;
}nodes[Max+1]; // 树(邻接表)
int C[Max+1]; // 树状数组
int N; // 节点数
int count;

// 函数
/*
* 映射 : 树->树状数组
* 即找到树中节点的偏序关系
*/
void DFS( const int id )
{
nodes[id].low = ++ count;
Edge* p = nodes[id].first;
while( p ) {
DFS( p->id );
p = p->next;
}
nodes[id].high = count;
}
/*
*  释放邻接表
*/
void Dispose()
{
for( int i = 1; i <= N; ++ i )
while( nodes[i].first ) {
Edge* s = nodes[i].first;
nodes[i].first = s->next;
delete s;
}
}
//-----------------树状数组操作------------------//
int TreeScope( const int x )
{
return ( x ^ (x - 1) ) & x;
}
void Update( int x, const int value )
{
while( x <= N ) {
C[x] += value;
x += TreeScope( x ); // 得到父节点
}
}
int GetSum( int x )
{
int sum = 0;
while( x > 0 ) {
sum += C[x];
x -= TreeScope( x ); // 得到兄弟节点
}
return sum;
}
//-----------------------------------------------//

int main()
{
scanf( "%d", & N );
memset( nodes, 0, sizeof(nodes) );
for( int i = 0; i < N - 1; ++ i ) {
int b, e;
scanf( "%d%d", & b, & e );
Edge* s = new Edge( e );
if( !nodes.first )
nodes[b].first = nodes[b].last = s;
else {
nodes[b].last->next = s;
nodes[b].last = s;
}
}
// 映射
count = 0;
DFS( 1 );
// 初始化树
for( int i = 1; i <= N; ++ i )
Update( i, 1 );
// M次操作
int M, x;
char ch;
scanf( "%d", & M );
while( M-- ) {
getchar();
scanf( "%c%d", & ch, & x );
switch( ch ) {
case 'C':{
if( nodes[x].is_picked ) { Update( nodes[x].low, 1 ); nodes[x].is_picked = false; }
else { Update( nodes[x].low, -1 ); nodes[x].is_picked = true; }
}break;
case 'Q':{
int num = GetSum( nodes[x].high ) - GetSum( nodes[x].low - 1 );
printf( "%d/n", num );
}break;
}
}
::Dispose();
return 0;
}

[b]PS : 树状数组中每个元素都记录并保持了它之前所有元素之和。

前i个元素之和 C[i]
区间[i,j]中元素之和 C[j] - C[i]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  apple tree struct c null user