POJ3321 Apple Tree(链式前向星+DFS序+树状数组)

题目链接

There is an apple tree outside of kaka’s house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree.The tree has N forks which are connected by branches. Kaka numbers the forks by 1 to N and the root is always numbered by 1. Apples will grow on the forks and two apple won’t grow on the same fork. kaka wants to know how many apples are there in a sub-tree, for his study of the produce ability of the apple tree.The trouble is that a new apple may grow on an empty fork some time and kaka may pick an apple from the tree for his dessert. Can you help kaka?

Input
The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.The following N - 1 lines each contain two integers u and v, which means fork u and fork v are connected by a branch.The next line contains an integer M (M ≤ 100,000).The following M lines each contain a message which is either “C x” which means the existence of the apple on fork x has been changed. i.e. if there is an apple on the fork, then Kaka pick it; otherwise a new apple has grown on the empty fork. or “Q x” which means an inquiry for the number of apples in the sub-tree above the fork x, including the apple (if exists) on the fork x. Note the tree is full of apples at the beginning

Output
For every inquiry, output the correspond answer per line.

1.题目大意:有一颗含有n个节点的树,其中1是根节点,每个节点最多长出一个Apple。初始时树上每个节点都有一个Apple,输入"C x"时,该节点上的Apple状态改变:如果有Apple,就摘下来,否则再长出一个。输入"Q x"时查询节点x及其子树下的苹果数量之和

2.一看题目,第一眼觉得是DFS,因为一个节点及其子树的节点和不就是一遍深搜的事情吗,但是问题是如何建树,这并不是二叉树,并不知道一个节点究竟会有多少个子节点。那么必须另谋出路,接着也许会想到线段树,但是线段树貌似也是基于二叉树的结构建树的。那么这时树状数组就发挥作用了
在这里插入图片描述
3.如上图这样的结构,如果我们查询节点1的子树节点和,那么显然是根节点和2,3,4子树的和,同理其他几个节点。我们可以这样做,设置两个数组L[],R[],分别记录每个节点的本身和子树中的最后一个节点。因为输入是随机输入的,因此我们要做的就是保存每个节点的出度,这就用到图论的基础知识了,但是此题的数据较大,因此最好使用链式前向星存每个点的子节点(出度)。接着跑一遍DFS就刚好得到下面对应的序列(以上图为例)
在这里插入图片描述
4.接下来就是树状数组的区间查询了,如果想改变一个节点的状态,那么就是修改区间{ L[x-1],L[x] },因为L数组存的就是该节点本身。如果查询一个区间和,就是查询区间{ L[x-1],R[x] },因为R数组存的就是每个节点的子树的最后一个节点

代码:

·

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define lowbit(x) (x&(-x))
const int maxn=1e5+10;
struct node{
    int next,to;
}edge[maxn];

int head[maxn],L[maxn],R[maxn],t[maxn];
int tot,n,m,num;

void addEdge(int u,int v){		//链式前向星的加边
    tot++;
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}

void init(){    
    tot=num=0;
    memset(head,0,sizeof head);
    memset(L,0,sizeof L);
    memset(R,0,sizeof R);
    memset(edge,0,sizeof edge);
}

void update(int i,int k){
    while(i<=n){
        t[i]+=k;
        i+=lowbit(i);
    }
}

int getSum(int i){
    int ans=0;
    for(;i;i-=lowbit(i)){
        ans+=t[i];
    }
    return ans;
}

void dfs(int cur){   //dfs求节点序
    L[cur]=++num;
    for(int i=head[cur];i;i=edge[i].next){
        dfs(edge[i].to);
    }
    R[cur]=num;
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int x,y;
    char op;
    init();
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>x>>y;
        addEdge(x,y);
        update(i,1);
    }
    update(n,1);
    dfs(1);
    //cout<<num<<endl;
    cin>>m;
    while(m--){
        cin>>op>>x;
        if(op=='C'){
            int res=getSum(L[x])-getSum(L[x]-1);
            if(res) update(L[x],-1);
            else update(L[x],1);
        }else{
            int ans=getSum(R[x])-getSum(L[x]-1);
            cout<<ans<<"\n";
        }
    }
    return 0;
}

发布了128 篇原创文章 · 获赞 7 · 访问量 5257

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/104692865