PKU 3321 Apple Tree(树状数组)

      一道很好的树状数组题目,题目的意思是给一树,刚开始每个节点有一个果子,有多次操作,每次操作若该点处有果子,则把果子摘了,否则该节点处添一个果子。每次询问以该节点为根的子树的果子数。题目的关键在于如何转化才能用树状数来解,比如我们要统计以i为根的子树的果数,能不能与树状数组中的Sum值联系起来呢?其实这样是可以的,如果重新编号,把该子树的节点的排在其左边,且知道最左边的节点的编号C1,该节点的编号为C2;那么其子树的果子数就为Sum(C2)-Sum(C1-1),这样问题就解决了。重新编号可以Dfs一次实现,分别求出每个点时间戳,C1以该节点的子树的开始记录也就是其子树中排在最左边的编号,C2表示该节点的编号。用vector超时了,自己重新学习写链表。

 

  
Memory: 8900K  Time: 1000MS
Language: G++  Result: Accepted

Source Code
#include "stdio.h"
#include "string.h"
#define Inf 100005
struct Link{
        int    v;
        Link   *next;
}*List[Inf];  
    
int n,a,b,r,cunt=1;
int C1[Inf],C2[Inf],C[Inf],S[Inf];
char str[3];
bool visited[Inf];

int lowbit(int x)
{
    return  x&(x^(x-1));
}   
void Dfs(int c)         //Dfs编号,记录每个节点开始值与结束值
{
     
         C1[c]=cunt;
         while(List[c])
         {
                int t=List[c]->v;      
                if(!visited[t])
                {
                    visited[t]=true;
                    Dfs(t);
                }   
                List[c]=List[c]->next;  
         }         
         C2[c]=cunt++;
}        

void Add(int x,int t)
{
      while(x<=n)
      {
           C[x]+=t;
           x+=lowbit(x);
      }
}

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

void Init()
{
         Link  *temp;
         for(int i=1;i<n;i++)
         {
                 scanf("%d%d",&a,&b);
                 temp=new Link;
                 temp->v=b;
                 temp->next=List[a];
                 List[a]=temp;
         }
}
                                           
int main()
{
       scanf("%d",&n);
       Init();
       Dfs(1);
       for(int i=1;i<=n;i++)
       {
                Add(i,1);
                S[i]=1;
       }     
       scanf("%d",&r);
       for(int k=1;k<=r;k++)
       {
              scanf("%s%d",str,&a);
              if(str[0]=='C')
              {     
                    S[C2[a]]=!S[C2[a]];
                    if(!S[C2[a]])   
                       Add(C2[a],-1);
                    else
                      Add(C2[a],1);    
              }
              else
                  printf("%d/n",Sum(C2[a])-Sum(C1[a]-1));
        }    
              
        return 0;  
}             
 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值