DFS序+树状数组

#include<bits/stdc++.h>
using namespace std;
int tr[10003],in[10003],ou[10003],fo[10003];
vector<int>edge[10003];
int n,m,key;
//修改节点k,添加代入1,删除代入-1
void add(int x,int val){
    while(x<=n){
        tr[x]+=val;
        x+=x&(-x);
    }
}
//得到1...x的和
int query(int x){
    int rec=0;
    while(x>0){
        rec+=tr[x];
        x-=x&(-x);
    }
    return rec;
}
//为每一个node添加一个左值和右值
void dfs(int node){
    in[node]=key;
    for(int i=0;i<edge[node].size();i++){
        key++;
        dfs(edge[node][i]);
    }
    ou[node]=key;
}
int main(){
    while(~scanf("%d",&n)){
        int a,b;char ch;
        for(int i=1;i<n;i++){
            cin>>a>>b;
            edge[a].push_back(b);
        }
        key=1;
        dfs(1);
        //为每一个节点对应一个左边界和右边界
        //他自己就存放在左边界里面
        //而它的管辖范围就是左边界到右边界
        for(int i=1;i<=n;i++){
            fo[i]=1;//最初每个Fork上都有一个苹果
            add(i,1);//同时更新树状数组的值
        }
        cin>>m;
        for(int i=0;i<m;i++){
            cin>>ch>>b;
            if(ch=='Q'){//b子树就是[Left[b],right[b]]
                int tmp=query(ou[b])-query(in[b]-1);
                cout<<tmp<<endl;
            }
            else{//每个节点编号就是它左值
                if(fo[b])add(in[b],-1);
                else add(in[b],1);
                fo[b]=!fo[b];//变为相反的状态
            }
        }
    }
    return 0;
}
Sample Input		Sample Output
3
1 2
1 3
3
Q 1				3
C 2
Q 1				2

DFS序+树状数组POJ3321 Apple Tree

题意:一颗树最初每个节点上都有一个苹果,有两种操作:修改(修改某一个节点,修改时这一个节点苹果从有到无,或从无到有)和查询(查询某一个节点他的子树上有多少个苹果)。由于此题数据比较大(N<=10^5),而且不是标准的二叉树,所以这里我们队每一个节点重新编号,另外为每一个节点赋一个左值和一个右值,表示这个节点的管辖范围。

上图也就是DFS搜索的时候做标记的过程,这样新的编号为1~6的节点所管辖的范围分别就是[1,6]  [2,4]   [3,3]  [4,4]  [5,6]  [6,6],其中左边的是左值,右边的是右值,节点1的区间是[1,6],正好这棵子树有6个节点,其他也一样。新的节点放进树状数组,求出每一个节点从1~左值-1的和和1~右值的和,他们的差就是这个节点的子树的所有的和(即这棵子树苹果数目)

 

猜你喜欢

转载自blog.csdn.net/cj1064789374/article/details/85381850
今日推荐