題意:
有一顆蘋果樹,每一個節點生長一個蘋果。有兩種操作,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;}