POJ 3321 Apple Tree

目录:

题意:

给你一颗苹果树,每棵树枝(节点)上都有一个苹果
先给你两个操作
Ca C a 表示a点的苹果去掉或者长出来(如果此时没长出来则去掉,如果此时去掉则长出来)
Qa Q a 表示询问这棵树上a以及a的所有子节点的苹果个数

分析:

这题需要把一个树形结构变换为线性结构,然后使用树状数组动态求和。变换方法为DFS一次这棵树,记录下每个节点第一次访问和最后一次访问时的顺序编号,这时,在某节点第一次访问和最后一次访问编号之间的访问编号,必定为该节点的子节点,按照访问编号建立树状数组,当改变某一节点苹果时,只需按照该节点第一次访问的编号在树状数组中修改值,查询时统计某节点在第一次访问和最后一次访问编号之间的和。
这里写图片描述

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
    int b,e,c;
}x[100001];
struct huangzhenbang{
    int u,v,next;
}t[200001];
int first[100001],last[100001],tf[100001],head[100001];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void change(int k,int c)
{
    while(k<=n)
    {
        x[k].c+=c;
        k+=lowbit(k);
    }
}
int sum(int k)
{
    int t=0;
    while(k>0)
    {
        t+=x[k].c;
        k-=lowbit(k);
    }
    return t;
}
//以上子程序为树状数组的
int len;
void add(int u,int v)
{
    t[++len].u=u;
    t[len].v=v;
    t[len].next=head[u];
    head[u]=len;

    t[++len].u=v;
    t[len].v=u;
    t[len].next=head[v];
    head[v]=len;
    return;
}
//add为建图
int w=0;
void dfs(int p)
{
    tf[p]=1;
    first[p]=++w;
    for(int i=head[p];i!=0;i=t[i].next)
    {
        if(tf[t[i].v]==0)
          dfs(t[i].v);
    }
    last[p]=w;
    return; 
}
//dfs用来求出每个节点的第一次访问和最后一次访问编号
int num[100001];
int main()
{
    n=read();
    int a,b;
    for(int i=1;i<n;i++)
    {
        a=read();b=read();
        add(a,b);//建图(双向)
    }
    dfs(1);
    for(int i=1;i<=n;i++)
      change(first[i],1);//先初始化树状数组
    int m=read();char ch;
    for(int i=1;i<=m;i++)
    {
        cin>>ch>>b;
        if(ch=='C')
        {
            if(num[first[b]]%2==0)//通过统计次数来判断当前是有还是无
              change(first[b],-1);
            else change(first[b],1);
            num[first[b]]++;//次数+1
        }
        else
        {
            int ans=sum(last[b]);
            if(first[b]>1)
              ans-=sum(first[b]-1);
            //求first~last,就用1~last减去1~(first-1)
            printf("%d\n",ans);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值