poj 3321 Apple Tree

要是你想做这个题,你首先要知道一个基(shen)本(qi)的性质:树上的每个子树的dfs序都是连续的
一个很显然的性质(知道了就不会忘了)

然后就可以做这个题啦

区间和用树状数组简单的维护一下就好

我的代码维护的是这个子树的空节点(就是没有苹果的节点),那么有苹果的节点数目就是(子树大小)-(空节点数)

(轮这个题的坑
(1. 数据范围绝对不止1e5,我开到了1e6才能过,而且数组开小了返回的还是TLE。。。。迷
(2. 这个题卡vector,用vector的可以改用一发其他的姿势了(比如前向星


然后然后感觉其他的也没有什么难想的地方


那么就这样



#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn = 1123456;

struct Edge{
    int next,to;
}edge[maxn];

int head[maxn],top;

void init(int n){
    memset(head,-1,sizeof(head));
    top=0;
}

void Link(int st,int ed){
    edge[top].to=ed;
    edge[top].next=head[st];
    head[st]=top++;
}

int siz[maxn],sid[maxn];
int _cnt;

void dfs(int st,int fa){
    siz[st]=1,sid[st]=_cnt++;
    for(int i = head[st];~i;i=edge[i].next){
        int x = edge[i].to;
        if(x!=fa){
            dfs(x,st);
            siz[st]+=siz[x];
        }
    }
}

void tinit(){
    _cnt=1;
    dfs(1,0);
}

int sum[maxn],hav[maxn];

void bitinit(){
    memset(sum,0,sizeof(sum));
    memset(hav,0,sizeof(hav));
}

int lowbit(int x){
    return x&(-x);
}

void add(int x,int d,int n){
    while(x<=n){
        sum[x]+=d;
        x+=lowbit(x);
    }
}

int que(int x){
    int ret = 0;
    while(x>0){
        ret += sum[x];
        x-=lowbit(x);
    }
    return ret;
}

void update(int x,int n){
    int d = hav[x]?-1:1;
    hav[x] = d==1;
    add(sid[x],d,n);
}

int query(int x){
    int val = que(siz[x]+sid[x]-1);
    val-=que(sid[x]-1);
    return siz[x]-val;
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        int x,y;
        init(n);
        for(int i=1;i<n;i++){
            scanf("%d %d",&x,&y);
            Link(x,y);
            Link(y,x);
        }
        tinit();
        bitinit();
//        for(int i=1;i<=n;i++)
//            printf(i<n?"%d ":"%d\n",sid[i]);
//        for(int i=1;i<=n;i++)
//            printf(i<n?"%d ":"%d\n",siz[i]);
        int m;
        char ord[10];
        scanf("%d",&m);
        while(m--){
            scanf("%s %d",ord,&x);
            if(ord[0]=='C')
                update(x,n);
            else
                printf("%d\n",query(x));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值