这篇文章写的很详细:
链接
这个b站上的视频讲的也很透彻:
链接
什么是树形数组:

树形数组是一种用来维护前缀和的工具,上图中序列上的就是树形数组,它虽然长得像个树,但是确是一个数组,比如上面的t[4]的值就是1-4的前缀和,其他元素以此类推。

add操作实现原理:

ask操作实现原理:

下面是区间查询+单点修改(1665and1666)的代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
inline int read()
{int s = 0, w = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();return s * w;
}
inline void write(ll x)
{if (x < 0) x = ~x + 1, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
ll lowbit(ll a)
{return a&(-a);//操作树形数组的核心,求的是二进制下的a从最低位开始一直到前面一个非0的数组成的10进制数
}
ll dat[100005],tree[100005];//dat是数据数组,tree是树形数组
ll n,q,op,p_l,w_r;
ll ask(ll r)
{ll ans=0;for(int j=r;j>=1;j-=lowbit(j))//j-=lowbit(j)是去了左上一层 {ans+=tree[j];  }return ans;
}//ask操作,求1-r的前缀和
void add(ll p,ll w)
{for(int j=p;j<=n;j+=lowbit(j))//用j+=lowbit(j)对每层进行操作 {tree[j]+=w;}
}//add操作,表现在dat数组上是让dat[p]+=w,表现在树形数组上是让含有dat[p]的项都加w
int main()
{n=read();q=read();for(int i=1;i<=n;++i){dat[i]=read();}for(int i=1;i<=n;++i){ll k=lowbit(i);for(int j=1;j<=k;++j){tree[i]+=dat[i-k+j];//树状数组储存 }}for(int i=1;i<=q;++i){op=read();p_l=read();w_r=read();switch(op){case 1:{write(ask(w_r)-ask(p_l)+dat[p_l]);//相减再补值得到区间和printf("\n");break;}case 2:{dat[p_l]+=w_r;//数据数组也要更改一下,求区间和时可能会拿来补值 add(p_l,w_r);break;}}}return 0;
}
/*
5 3
0 0 0 0 0
2 1 100
2 2 1000
1 2 5
*/

下面是另一种构建树状数组的方法(这种比较好,上面那种是我自己按照意思写的):

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
inline int read()
{int s = 0, w = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();return s * w;
}
inline void write(ll x)
{if (x < 0) x = ~x + 1, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
ll lowbit(ll a)
{return a&(-a);//操作树形数组的核心,求的是二进制下的a从最低位开始一直到前面一个非0的数组成的10进制数
}
ll dat[100005],tree[100005];//dat是数据数组,tree是树形数组
ll n,q,op,p_l,w_r;
ll ask(ll r)
{ll ans=0;for(int j=r;j>=1;j-=lowbit(j))//j-=lowbit(j)是去了左上一层 {ans+=tree[j];  }return ans;
}//ask操作,求1-r的前缀和
void add(ll p,ll w)
{for(int j=p;j<=n;j+=lowbit(j))//用j+=lowbit(j)对每层进行操作 {tree[j]+=w;}
}//add操作,表现在dat数组上是让dat[p]+=w,表现在树状数组上是让含有dat[p]的项都加w
int main()
{n=read();q=read();for(int i=1;i<=n;++i){dat[i]=read();add(i,dat[i]);//树状数组储存 }for(int i=1;i<=q;++i){op=read();p_l=read();w_r=read();switch(op){case 1:{write(ask(w_r)-ask(p_l)+dat[p_l]);//相减再补值得到区间和printf("\n");break;}case 2:{dat[p_l]+=w_r;//数据数组也要更改一下,求区间和时可能会拿来补值 add(p_l,w_r);break;}}}return 0;
}
/*
5 3
0 0 0 0 0
2 1 100
2 2 1000
1 2 5
*/

下面是区间修改+区间查询(1667and1668)的代码:
听说这种题用线段树比较好解= =,我用树状数组也就是套了个公式(蒟蒻瑟瑟发抖)。

其中tree1维护了差分数组b[i]的前缀和,tree2维护了i*b[i]的前缀和,sum是数据数组a的前缀和。代码中没有写出差分数组b是因为可以利用树状数组不用写出而直接求其前缀和。

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll a[1000005],sum[1000005],tree1[1000005],tree2[1000005];
ll n,q,op,l,r,w;
inline int read()
{int s = 0, w = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();return s * w;
}
inline void write(ll x)
{if (x < 0) x = ~x + 1, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
ll lowbit(ll a)
{return a&(-a);
}
ll ask1(ll r)
{ll ans=0;for(int i=r;i>=1;i-=lowbit(i)){ans+=tree1[i];    }return ans;
}
ll ask2(ll r)
{ll ans=0;for(int i=r;i>=1;i-=lowbit(i)){ans+=tree2[i];}return ans;
}
void add1(ll p,ll w)
{for(int i=p;i<=n;i+=lowbit(i)){tree1[i]+=w;}
}
void add2(ll p,ll w)
{for(int i=p;i<=n;i+=lowbit(i)){tree2[i]+=w;}
}
int main()
{n=read();q=read();for(int i=1;i<=n;++i){a[i]=read();if(i==1) sum[i]=a[i];else sum[i]=sum[i-1]+a[i];}for(int i=1;i<=q;++i){op=read();switch(op){case 1:{l=read();r=read();write((sum[r]+(r+1)*ask1(r)-ask2(r))-(sum[l-1]+l*ask1(l-1)-ask2(l-1)));printf("\n");break;}case 2:{l=read();r=read();w=read();add1(l,w);add1(r+1,-w);add2(l,l*w);add2(r+1,-(r+1)*w);break;}}}return 0;
}

SDNUOJ 1665-1668(树状数组的应用)相关推荐

  1. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  2. Color the ball(HDU1556)树状数组

    每次对区间内气球进行一次染色,求n次操作后后所有气球染色次数. 树状数组,上下区间更新都可以,差别不大. 1.对于[x,y]区间,对第x-1位减1,第y位加1,之后向上统计 #include<b ...

  3. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  4. Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)

    题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...

  5. poj_3067 树状数组

    题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M.现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个 ...

  6. hdu 1166 敌兵布阵(树状数组)

    题意:区间和 思路:树状数组 #include<iostream> #include<stdio.h> #include<string.h> using names ...

  7. Equalizing Two Strings 冒泡排序or树状数组

    首先考虑排序后相等 如果排序后相等的话就只考虑reverse长度为2的,所以a或者b排序后存在相邻两个字母相等的话就puts YES,n>26也直接puts YES 不然的话就假设c为a,b排完 ...

  8. Hdu 6534 Chika and Friendly Pairs 莫队算法+树状数组

    题目链接 题意求给区间[L,R]中有少对(i,j)满足i<j且abs(a[i]-a[j])<=k. 首先来说暴力的方法就是离散化,然后用树状数组来维护,但是m次询问,m很大,所以说一定会t ...

  9. HDU - 5877 Weak Pair 2016 ACM/ICPC 大连网络赛 J题 dfs+树状数组+离散化

    题目链接 You are given a rootedrooted tree of NN nodes, labeled from 1 to NN. To the iith node a non-neg ...

最新文章

  1. python 编程一日一练-Python每日一练0013
  2. 剑指Offer #14 链表中倒数第k个结点(快慢指针) | 图文详解
  3. UVA - 10934 Dropping water balloons(装满水的气球)(dp)
  4. 寒假作业 使用xmind脑图小结课程内容
  5. mini2440驱动分析之PWM
  6. 北信源管理网页卸载密码_怎么卸载找不到程序的流氓软件?
  7. 第七篇 ScrollView控件
  8. python KM算法
  9. SoundTouch音频处理库
  10. Aspect基础使用方法
  11. 【HDU5442】 Favorite Donut(后缀数组)
  12. 创始人李卉:麦客CRM2.0核心逻辑及其背后的思考
  13. vscode关闭讨厌的单词拼写检查
  14. JAVA程序设计题——英雄对战游戏,定义一个描述战斗单位的英雄(Hero)类,此类必须包含以下成员变量:名称(name),生命值(life),技能1攻击力(damage1),防御力(defence)
  15. Apollo代码学习(二)—车辆运动学模型
  16. 递归函数求解阶层(C语言)
  17. Mathematica里面总有一些炫的特征
  18. 求double类型的立方根_二分法逼近
  19. 包引入报错 ImportError: cannot import name ‘best_partition‘ from ‘community‘
  20. 计算机考试考前培训怎么弄,关于2016年下半年全国计算机等级考试考前培训实施方案...

热门文章

  1. 整理chinaUnix上【你职业生涯中最难忘的误操作】
  2. 计算机界面打不了五笔,64位win7五笔输入法无法使用怎么办_win7电脑五笔输入法无法使用如何解决-win7之家...
  3. 转盘式视觉筛选机及其图像识别系统
  4. MATLAB画双纵轴曲线。
  5. 爬虫 http原理,梨视频,github登陆实例,requests请求参数小总结
  6. Windows 10 Mscomctl.ocx缺失解决方法
  7. 体验华为操作系统 openEuler 20.03 LTS linux
  8. 信息安全考研和就业的选择分析
  9. 购物车原生js简单明了
  10. linux下的外接显示器设置成竖屏