POJ 3321 Apple Tree(DFS+树状数组)

超级传送门:http://poj.org/problem?id=3321


题意:有一棵苹果树,每个分叉的交点或者末端刚开始都长有苹果,这些苹果可以被吃掉,也可以再长出来,但是每个位置上同时最多只有一个苹果。现在要查询指定的某棵子树上的苹果树。


分析:典型的树状数组求和问题,但是刚看题感觉很棘手,如何把一棵树映射到树状数组里?这里采用DFS改时间戳的方法,记两个数组begin和end,用begin[i]表示以i为根的子树遍历的第一个点,end[i]表示以i为根的子树遍历的最后一个点。

比如数据为:

5

1 2 

2 5 

2 4 

1 3


那么begin[] = {1, 2, 5, 4, 3}, end[] = {5, 4, 5, 4, 3},下标从1开始。

对于每个点都对应一个区间(begin[i], end[i]),如果要改变点a的状态,只要update(begin[a]),要求该子树的苹果树,即getsum(end[a] ) - getsum(begin[a] - 1)。

注意此题用vector建树会TLE,所以我用数组建树,最大分支数只开了20,比较危险,如果卡到分支数很大的数据就悲剧了,还好AC了。最好还是自己用结构体和指针动态建树。


代码:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 100005;
int c[maxn],a[maxn],begin[maxn],end[maxn],vis[maxn];
int t;
int tree[maxn][20],branchNum[maxn];
int n;
int lowbit(int t) {
    return t & -t;
}
int getsum(int end) {
    int ret = 0;
    for (int i=end;i>=1;i-=lowbit(i)) {
        ret += c[i];
    }
    return ret;
}
void update(int p,int val) {
    for (int i=p;i<maxn;i+=lowbit(i)) {
        c[i] += val;
    }
}
void dfs(int p) {
    if (vis[p]) return;
    vis[p] = 1;
    t++;
    begin[p] = t;
    for (int i=0;i<branchNum[p];i++) {
        int x = tree[p][i];
        dfs(x);
    }
    end[p] = t;
    return;
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen("1.txt","r",stdin);
    #endif
    int x,y,q;
    char cmd[5];
    while (scanf("%d",&n)>0 && n) {
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
        memset(branchNum,0,sizeof(branchNum));
        for (int i=1;i<=n;i++) {
            memset(tree[i],0,sizeof(tree[i]));
            a[i] = 1;
        }
        for (int i=1;i<=n-1;i++) {
            scanf("%d%d",&x,&y);
            tree[x][branchNum[x]++] = y;
        }
        t = 0; //时间戳
        dfs(1);
        for (int i=1;i<=n;i++) {
            update(begin[i],1);
        }
        scanf("%d",&q);
        while (q--) {
            scanf("%s%d",cmd,&x);
            if (cmd[0]=='Q') {
                printf("%d\n",getsum(end[x])-getsum(begin[x]-1));
            } else if (cmd[0]=='C') {
                if (a[x]) {
                    update(begin[x],-1);
                    a[x] --;
                } else {
                    update(begin[x],1);
                    a[x] ++;
                }
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章