poj 3321 树状数组

首先对数进行DFS一下,前序优先遍历,这样做的目的是令节点i的子节点的编号组成的集合是一段连续的数,这样在查询的时候就能够用树状数组来查询连续的区间的和

AC代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAX_N = 100000 + 5;

struct Edge{
    int to;
    int next;
};

Edge edge[MAX_N*4];
int head[MAX_N], tot;
int N;
int sum[MAX_N], statu[MAX_N];
int st[MAX_N], ed[MAX_N];
int now_id;

void add_edge( int a, int b ){
    edge[tot].to = b;
    edge[tot].next = head[a];
    head[a] = tot++;
}

inline int lowbit( int x ){
    return x&-x;
}

int getsum( int x ){
    int ans = 0;
    while( x > 0 ){
        ans += sum[x];
        x -= lowbit( x );
    }
    return ans;
}

void updata( int x, int val ){
    while( x <= MAX_N ){
        sum[x] += val;
        x += lowbit( x );
    }
}

void DFS( int x ){
    st[x] = ++now_id;
    for( int i = head[x]; i != -1; i = edge[i].next ){
        int to = edge[i].to;
        DFS( to );
    }
    ed[x] = now_id;
}

int main(){
    int M;
    while( scanf( "%d", &N ) != EOF ){
        memset( head, -1, sizeof( head ) );
        for( int i = 1; i < N; i++ ){
            int temp1, temp2;
            scanf( "%d%d", &temp1, &temp2 );
            add_edge( temp1, temp2 );
        }
        now_id = 0;
        DFS( 1 );
        for( int i = 1; i <= N; i++ ){
            statu[i] = 1;
            updata( st[i], 1 );
        }
        scanf( "%d", &M );
        char s[10];
        int t;
        for( int i = 0; i < M; i++ ){
            scanf( "%s%d", s, &t );
            if( s[0] == 'Q' ){
                int ans = getsum( ed[t] ) - getsum( st[t] - 1 );
                printf( "%d\n", ans );
            }else{
                if( statu[t] == 1 ){
                    updata( st[t], -1 );
                }else{
                    updata( st[t], 1 );
                }
                statu[t] ^= 1;
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值