树状数组的理解(前缀和 and 差分)
二更——
有神仙反映数星星那个题外链炸了,我决定把图给你们粘一下,汉语翻译的话在一本通提高篇的树状数组那一章里有,同时也修改了一些汉语语法的错误
这段时间学了线段树组,当神仙们都在学kmp和hash的时候,我这个蒟蒻致远星了,,,,,所以在补完字符串算法之后我决定再补一补数据结构
这篇总结主要就是给自己看的,所以树状数组的原理请移步这篇
高赫奆佬的blogs
这篇以例题为主
首先是一道板子题
P3374 【模板】树状数组 1
这个题是个板子
让我们来看一看树状数组的一些操作
1.对某一个点添加某个值
void update(int x,int y)
{
while(x <= n){
t[x] += y;
x += lowbit(x);
}
}
考虑树状数组t[ x] 表示区间[x-lowbit(x)+1,x]之间所有数的和,又因为所有x为2的整倍数的t数组的值都来自于前面2的整倍数的贡献,所以我们要把每一个lowbit(x)都进行添加x值
如果你看不懂,可以看看这个图
2.还有就是查询某个区间的值
我们肯定知道在前缀和中[x,y]这个区间的值就是sum(y)-sum(x-1)对吧,然后我们只需要写出来sum函数就可以了
int sum(int x)
{
int res = ;
while(x>){
res += t[x];
x -= lowbit(x);
}
return res;
}
还有就是快速求lowbit(x)的值的代码
int lowbit(int x)
{
return x & (-x);
}
这样我们这道板子题就差不多完事了
放一下代码吧
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, t[];
int lowbit(int x)
{
return x & (-x);
}
void update(int x,int y)
{
while(x <= n){
t[x] += y;
x += lowbit(x);
}
}
int sum(int x)
{
int res = ;
while(x>){
res += t[x];
x -= lowbit(x);
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = , v; i <= n; ++i){
scanf("%d", &v);
update(i,v);
}
for (int i = , temp, u, v; i <= m; ++i){
scanf("%d%d%d", &temp, &u, &v);
if(temp == ) update(u,v);
else printf("%d\n",sum(v) - sum(u - ));
}
return ;
}
下面来看到第二个板子
P3368 【模板】树状数组 2
这个题换了一个问法,问的是某几个数的差,所以我们再添加差分这个元素
把原本p[x]表示的意思变为[x-lowbiut(x)+1,x]这个区间右端点与左端点的差,因为还是按照lowbit(x)来倍增的,所以我们能够通过sum这个函数来求得任意两个数的差分值,然后相减就能得到所求数字,不明白的话,我慢慢讲来。
首先sum和update的方法是不变的,但是因为我们对于一个区间内的所有数都加z,所以这个区间内的差分值是不变的,我们只对左端点的差分值加z,右端点+1的位置的差分值-z就行了
update(l,z);
update(r + ,-z);
想要求某一个数的话,直接将这个数到1所有的差分值相加即可求得,也就是sum(x)
这个题就完事啦
#include <iostream>
#include <cstdio>
using namespace std;
long long n, m,t[];
inline int lowbit(int x)
{
return x & (-x);
}
inline void update(int x,int y)
{
while(x<=n){
t[x] += y;
x += lowbit(x);
}
}
inline int sum(int x)
{
int res = ;
while(x){
res += t[x];
x -= lowbit(x);
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
int now,past = ;
for (int i = ; i <= n; ++i){
scanf("%d", &now);
update(i,now - past);
past = now;
}
for (int i = ,k; i <= m;++i){
scanf("%d", &k);
if(k == ){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
update(x,z);
update(y + ,-z);
}
else{
int x;
scanf("%d", &x);
printf("%d\n", sum(x));
}
}
return ;
}
还有一道比较好玩的题目
这个题的大体意思就是给你星星的坐标,在星星左下方的(包括正左和正下)的星星有k颗,那么这个星星就是k级的,问每一级星星的数量,星星的坐标按照y轴升序输入,y轴相同的按x轴升序输入
怎么说呢,一看到坐标肯定先想到二维数组,但是数据范围在这个地方了,你肯定是不能开p[15000][15000]的,我们再看看这个题,他的输入很棒啊,保证了后输入的一定是把之前输入的星星包含在内了,所以我们就可以用a[x] 表示横坐标为x的星星的个数,然后跑一遍统计一下就可以辣
上代码
这地方有个坑,就是星星的坐标可以是(0,0)但是我们跑前缀和的时候因为有lowbit(x)操作,下标必须从1开始,所以我们把每一个读进来的x都++,这样的话不仅不影响最终结果,而且也不会出锅啦
#include <stdio.h>
#include <stdlib.h>
#include <string.h> using namespace std; int c[];
int level[]; //求2的K次幂
int lowbit(int t)
{
return t&(-t);
}
//更新树状数组
void update(int t)
{
while(t<)
{
++c[t];
t+=lowbit(t);
}
}
//获取前N项和
int getSum(int t)
{
int sum = ;
while(t>)
{
sum+=c[t];
t-=lowbit(t);
}
return sum;
}
int main()
{
int n;
int x;
int y;
int i;
int sum; scanf("%d",&n); memset(c,,sizeof(c));
memset(level,,sizeof(c)); for(i = ;i<n;i++)
{
scanf("%d%d",&x,&y);
++x;//星星的左边可以从0开始,但是update函数的参数却不能是0,所有向后移一位
update(x);
sum = getSum(x);
++level[sum];
}
for(i = ;i<n;i++)
{
printf("%d\n",level[i+]);
}
return ;
}
ok 完事~
树状数组的理解(前缀和 and 差分)的更多相关文章
- 树状数组+二维前缀和(A.The beautiful values of the palace)--The Preliminary Contest for ICPC Asia Nanjing 2019
题意: 给你螺旋型的矩阵,告诉你那几个点有值,问你某一个矩阵区间的和是多少. 思路: 以后记住:二维前缀和sort+树状数组就行了!!!. #define IOS ios_base::sync_wit ...
- HDU 5465——Clarke and puzzle——————【树状数组BIT维护前缀和+Nim博弈】
Clarke and puzzle Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- [POI2005]AUT-The Bus 树状数组维护最大前缀和
#include<cstdio> #include<algorithm> using namespace std; const int N=100000+3; int x[N] ...
- [POI2007]MEG-Megalopolis 树状数组 + dfs序前缀和 好题
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const ...
- HH的项链 树状数组动态维护前缀
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const ...
- 1042.D Petya and Array 前缀 + 树状数组
11.19.2018 1042.D Petya and ArrayNew Point: 前缀 + 树状数组 :树状数组逐个维护前缀个数 Describe: 给你一个数组,一个标记数,问你有多少区间[l ...
- bzoj4397【Usaco2015 Dec】Breed Counting(前缀和、树状数组)
题目描述 Farmer John's N cows, conveniently numbered 1…N, are all standing in a row (they seem to do so ...
- HDU 3303 Harmony Forever 前缀和+树状数组||线段树
Problem Description We believe that every inhabitant of this universe eventually will find a way to ...
- CDQ分治总结(CDQ,树状数组,归并排序)
闲话 CDQ是什么? 是一个巨佬,和莫队.HJT(不是我这个蒟蒻)一样,都发明出了在OI中越来越流行的算法/数据结构. CDQ分治思想 分治就是分治,"分而治之"的思想. 那为什么 ...
随机推荐
- 090、ELK完成部署和使用 (2019-05-13 周二)
参考https://www.cnblogs.com/CloudMan6/p/7787870.html 上节我们已经部署了容器化的ELK,本节我们学习如何将日志导入ELK并进行图形化展示. 几乎 ...
- c#委托(Delegates)--基本概念及使用
在我这菜鸟理解上,委托就是可以用方法名调用另一方法的便捷方法,可以简化switch等语句的重复.最近做项目的时候恰好需要用到委托,便来复习及学习委托的使用.嗯...本人以前并没有用过,只是稍微知道而已 ...
- springboot学习1
gradle环境配置 https://www.w3cschool.cn/gradle/ctgm1htw.html Spring profile 多环境配置管理 参考:https://www.cnblo ...
- 扫描全能王 v5.13.0.20190916 去水印和广告版
说明 1.先安装1(安装完不要打开),再安装2,然后打开2,参考下图: 2.不要登录扫描全能王账号,否则会导致失败! 3.激活完成后可以卸载2 下载地址 城通网盘 蓝奏云(仅含1) 百度网盘 另外口袋 ...
- 003-SaltStack入门篇之远程执行和配置管理
第一条命令: [root@linux-node1 master]# salt '*' test.ping linux-node2.example.com: True linux-node1.examp ...
- 模拟赛小结:2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest
2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest 2019年10月11日 15:35-20:35(Solved 8,Penalty 675 ...
- Educational Codeforces Round 42 (Rated for Div. 2) E. Byteland, Berland and Disputed Cities(贪心)
E. Byteland, Berland and Disputed Cities time limit per test2 seconds memory limit per test256 megab ...
- jlink commander使用
1.将JLink.exe拷贝到某个文件夹底下 2.建立bat文件,内容如下: JLink.exe -device Cortex-A7 -if JTAG -speed 4000 -jtagconf -1 ...
- VS插件CodeRush for Visual Studio发布v19.1.5|新的Inline Lambda重构
CodeRush是一个强大的Visual Studio .NET 插件,它利用整合技术,通过促进开发者和团队效率来提升开发者体验.CodeRush能帮助你以极高的效率创建和维护源代码.Consume- ...
- Python 变量类型 Ⅱ
Python字符串 字符串或串(String)是由数字.字母.下划线组成的一串字符. 一般记为 : s="a1a2···an"(n>=0) 它是编程语言中表示文本的数据类型. ...