Apple Tree 树状数组习题

这篇博客主要介绍了如何使用C++实现树状数组解决Apple Tree问题,作为数据结构与算法期末复习的内容。博主参考了他人代码并进行理解,提供了带注释的C++实现,重点在于理解和应用树状数组的单点更新和区间求和操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Apple Tree Poj (数据结构与算法期末复习)

题目链接:http://dapractise.openjudge.cn/2019hwall/003/

在这里插入图片描述
在这里插入图片描述

树状数组,单点更新,区间求和

代码是看了这位大佬的,https://www.cnblogs.com/gj-Acit/p/3236843.html
所以几乎就是把他的代码理解了一遍,然后自己再用C++写了一遍改动了一丢丢再加了点注释应该会稍微好懂一点。(树状数组的PPT看完了就应该可以不需要太费脑去看懂这个代码了吧)

代码
#include <iostream>
#include<vector>
#include<string.h>
using namespace std;
#define MAXL 100005
typedef vector<int> VE;
vector<VE> edge(MAXL);//用于存储边
int Left[MAXL], Right[MAXL], Fork[MAXL], C[MAXL];
//Left,Right分别是一个Fork的左右边界(可以相等)
//Fork中0代表空,1代表有苹果;C其实是对Fork数组的相应树状数组
int n, m, key;
int lowbit(int t)
{
 return (t & -t);
}
void DFS(int t)//深度优先搜索得到苹果树的每个Fork的起始位置和终止位置
{
 Left[t] = key;
 int k = edge[t].size();
 for (int i = 0; i < k; i++)
 {
  key++;
  DFS(edge[t][i]);
 }
 //key++;//如果加上这个就需要扩大数组并且修改代码,且结果除2
 Right[t] = key;//右边的边界不占位置
}
int getsum(int t)
{
 int sum = 0;
 while (t >0)
 {
  sum += C[t];
  t = t - lowbit(t);
 }
 return sum;
}
void Update(int t)
{
 if (Fork[t] == 1){
  Fork[t] = 0;
  while (t <= n) {
   C[t]--;
   t = t + lowbit(t);
  }
 }
 else{
  Fork[t] = 1;
  while (t <= n) {
   C[t]++;
   t = t + lowbit(t);
  }
 }
}
int main()
{
 memset(Fork, 0, sizeof(Fork));
 memset(Left, 0, sizeof(Left));
 memset(Right, 0, sizeof(Right));
 memset(C, 0, sizeof(C));
 for (int i = 0; i < n - 1; i++) {
  edge[i].clear();
 }
 cin >> n;
 int a, b;
 for (int i = 0; i < n - 1; i++){
  cin >> a >> b;
  edge[a].push_back(b);
 }
 key = 1;
 DFS(1);
 for (int i = 1; i <= n; i++){
  Update(i);//把初始状态输入,即每个分支都有苹果
 }
 char op;
 int t;
 cin >> m;
 for (int i = 0; i < m; i++){
  cin >> op >> t;
  //cout << op << " " << t << endl;
  if (op == 'Q'){
   cout << (getsum(Right[t]) - getsum(Left[t] - 1)) << endl;
   /*只有左边的有增加key而右边的没有加key,所以不需要除2*/
  }
  else {
   Update(Left[t]);
   /*这里本来我是Update(t)也过了示例,但是WA了,才发现应该用Left[t],因为Left[t]对应了
   在Fork数组中t的初始位置,所以应该修改这个值对应的Fork值和相应的C树状数组值*/
  }
 }
}

这代码缩进怎么这么小。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值