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;
}


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