Apple Tree POJ3321 dfs序 + 树状数组

  • 题意
    卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果。卡卡很喜欢苹果。树上有N个节点,卡卡给他们编号1到N,根的编号永远是1.每个节点上最多结一个苹果。卡卡想要了解某一个子树上一共结了多少苹果。现在的问题是不断会有新的苹果长出来,卡卡也随时可能摘掉一个苹果吃掉。你能帮助卡卡吗?

在这里插入图片描述

  • 解题思路
    此题我们的想法肯定是想将查询和修改都降为 l o g n logn logn的复杂度,这区间查询单点修改正好用树状数组或线段树解决即可。关键我们怎么将树转化为区间,即每颗子树都附上区间, d f s dfs dfs可以帮我们解决这个问题,我们需要对每个结点设置一个 s t [ u ] , e d [ u ] st[u],ed[u] st[u],ed[u],这代表了我们从 u u u结点出发的 d f s dfs dfs,即 u u u d f s dfs dfs序,而从 d f s dfs dfs完成之后 u u u的子树也走完了,我们就要用 e d [ u ] ed[u] ed[u]来表示区间结束的编号。至此,通过 d f s dfs dfs编序即解决了这个问题。

  • AC代码

/**
  *@filename:A
  *@author: pursuit
  *@created: 2021-08-11 21:09
**/
#include <iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n,m,u,v;
int ans[N],st[N],ed[N],num;//st[u]表示的为起始dfs序,ed[u]表示以u为结点的子树的终止dfs序,即子树的最大编号。
struct node{
    int to,next;
}edges[N];
int tot,head[N];
bool vis[N];
void add(int u,int v){
    edges[++tot].to = v;
    edges[tot].next = head[u];
    head[u] = tot;
}
void dfs(int u,int fu){
    st[u] = ++ num;
    for(int i = head[u]; i; i = edges[i].next){
        int v = edges[i].to;
        if(v == fu)continue;
        dfs(v,u);
    }
    ed[u] = num;
}
int lowbit(int x){
    return x & (- x);
}
void insert(int x,int value){
    while(x <= n){
        ans[x] += value;
        x += lowbit(x);
    }
}
int sum(int x){
    int res = 0;
    while(x > 0){
        res += ans[x];
        x -= lowbit(x);
    }
    return res;
}
void solve(){
    dfs(1,1);
    for(int i = 1; i <= n; ++ i){
        insert(st[i],1);
    }
    scanf("%d", &m);
    char op;
    int x;
    while(m -- ){
        scanf(" %c%d", &op, &x);
        if(op == 'C'){
            insert(st[x],vis[x] ? -1 : 1);
            vis[x] ^= 1;
        }
        else{
            printf("%d\n", sum(ed[x]) - sum(st[x] - 1));
        }
    }
}
int main(){	
    scanf("%d", &n);
    memset(vis,true,sizeof(vis));
    memset(head,0,sizeof(head));
    tot = num = 0;
    for(int i = 1; i < n; ++ i){
        scanf("%d%d", &u, &v);
        add(u,v);
    }
    solve();
    return 0;
}
posted @ 2022-03-26 16:48  unique_pursuit  阅读(30)  评论(0)    收藏  举报