POJ 3321 树映射到树状数组

来源:互联网 发布:相机照片数据恢复 编辑:程序博客网 时间:2024/05/16 02:09

题意:

有一颗苹果树,每一个节点生长一个苹果。有两种操作,Q(x) 输出某个节点的子树上一共有多少个苹果; C(x)存在苹果则摘下来,不存在则生出一个苹果。


题解:

很容易想到树状数组,而建立映射是关键。进行搜索给所有的节点编号,求出每一个节点管辖的范围(需包括节点本身和它子树上的所有节点)。然后只需对这些管辖区间进行维护,用树状数组。正如下图所示,每一个节点(即树杈)的编号是先序遍历的序号,标注在节点内部;而每个节点的管辖范围则是[low,high],low=节点编号


#include <iostream>using namespace std;#define N 100005bool vis[N], check[N];int c[N], dep, k, n;struct treeNode{int id;treeNode *brother;treeNode *son;} node[N], store[N];struct range{int low, high;} ran[N];int lowbit ( int x ){return x & ( -x );}void update ( int r, int val ){for ( int i = ran[r].low; i <= n; i += lowbit(i) )c[i] += val;        /* for ( i = ran[r].high+1; i <= n; i += lowbit(i) )                c[i] -= val;       一开始wrong再这里,这两句不该有啊 */}int getSum ( int x ){int i, sum1 = 0, sum2 = 0;for ( i = ran[x].low - 1; i > 0; i -= lowbit(i) )sum1 += c[i];for ( i = ran[x].high; i > 0; i -= lowbit(i) )sum2 += c[i];return sum2 - sum1;}void dfs ( int r ){vis[r] = true;ran[r].low = ++dep;treeNode *temp = node[r].son;while ( temp != NULL ){if ( vis[ temp->id ] == false )dfs ( temp->id );temp = temp->brother;}ran[r].high = dep;}int main(){char oper[5];int m, u, v, x, i;dep = k = 0;memset(node,NULL,sizeof(node));memset(store,NULL,sizeof(store));memset(ran,0,sizeof(ran));memset(vis,0,sizeof(vis));memset(c,0,sizeof(c));scanf("%d",&n);for ( i = 1; i < n; ++i ){scanf("%d%d",&u,&v);if ( node[u].son == NULL ){node[u].son = &store[k++];node[u].son->id = v;}else{    treeNode *temp = &store[k++];    temp->id = v;temp->brother = node[u].son->brother;    node[u].son->brother = temp;}}dfs(1);for ( i = 1; i <= n; ++i ){update ( i, 1 );check[i] = true;}scanf("%d",&m);while ( m-- ){scanf("%s",oper);scanf("%d",&x);if ( oper[0] == 'Q' )printf("%d\n",getSum(x));else{if ( check[x] == true )update ( x, -1 );elseupdate ( x, 1 );check[x] = !check[x];}}return 0;}


原创粉丝点击