目录

1.树状数组的引入

2.基本操作:主要包括 插入操作,查询操作.

3.具体实现:

例题:1.楼兰图腾

241. 楼兰图腾

2.一个简单的整数问题

3.一个简单的整数问题2


1.树状数组的引入

树状数组是用来解决区间修改-单点查询以及单点修改-区间查询和区间修改-区间查询问题的一种优化时间的算法。

这里推荐B站视频歪瑞古德:〔manim | 算法 | 数据结构〕 完全理解并深入应用树状数组 | 支持多种动态维护区间操作_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1pE41197Qj?from=search&seid=13866619238299900297&spm_id_from=333.337.0.0

简单来说,如果一个问题能转变成上述三个问题,就可以使用树状数组,将修改和查询操作的时间复杂度从O(n)优化到O(log n),树状数组是一种简单的数据结构。

2.基本操作:主要包括 插入操作,查询操作.

3.具体实现:

这里以区间求和问题作为例子。

也就是区间修改,区间求和

插入操作:

void add(int tr[],int x,int c){for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}

查询操作:

int sum(int tr[],int x){int res=0;for(int i=x;i;i-=lowbit(i)) res+=tr[i];return res;
}

例题:1.楼兰图腾

如何把一个问题转换成区间修改,区间查询,是解决树状数组问题的关键,另外能用树状数组解决的问题也可以用线段树解决。

241. 楼兰图腾

  • 题目https://www.acwing.com/problem/content/description/243/
  • 提交记录
  • 讨论
  • 题解
  • 视频讲解

在完成了分配任务之后,西部 314 来到了楼兰古城的西部。

相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V),一个部落崇拜铁锹(),他们分别用 V 和  的形状来代表各自部落的图腾。

西部 314 在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 n 个点,经测量发现这 n 个点的水平位置和竖直位置是两两不同的。

西部 314 认为这幅壁画所包含的信息与这 nn 个点的相对位置有关,因此不妨设坐标分别为 (1,y1),(2,y2),…,(n,yn),其中 y1∼yn是 1 到 n 的一个排列。

西部 314314 打算研究这幅壁画中包含着多少个图腾。

如果三个点 (i,yi),(j,yj),(k,yk) 满足 1≤i<j<k≤n且 yi>yj则称这三个点构成 V 图腾;

如果三个点 (i,yi),(j,yj),(k,yk)满足 1≤i<j<k≤n且 yi<yj,则称这三个点构成  图腾;

西部 314想知道,这 n个点中两个部落图腾的数目。

因此,你需要编写一个程序来求出 V 的个数和  的个数。

输入格式

第一行一个数 n。

第二行是 n 个数,分别代表 y1,y2,…,yn。

输出格式

两个数,中间用空格隔开,依次为 V 的个数和  的个数。

数据范围

对于所有数据,n≤200000,且输出答案不会超过 int64。
y1∼yn是 1 到 n 的一个排列。

输入样例:

5
1 5 3 2 4

输出样例:

3 4
#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;const int N = 2000010;typedef long long LL;int n;
//t[i]表示树状数组i结点覆盖的范围和
int a[N], t[N];
//Lower[i]表示左边比第i个位置小的数的个数
//Greater[i]表示左边比第i个位置大的数的个数
int Lower[N], Greater[N];//返回非负整数x在二进制表示下最低位1及其后面的0构成的数值
int lowbit(int x)
{return x & -x;
}//将序列中第x个数加上k。
void add(int x, int k)
{for(int i = x; i <= n; i += lowbit(i)) t[i] += k;
}
//查询序列前x个数的和
int ask(int x)
{int sum = 0;for(int i = x; i; i -= lowbit(i)) sum += t[i];return sum;
}int main()
{scanf("%d", &n);for(int i = 1; i <= n; i++) scanf("%d", &a[i]);//从左向右,依次统计每个位置左边比第i个数y小的数的个数、以及大的数的个数for(int i = 1; i <= n; i++){int y = a[i]; //第i个数//在前面已加入树状数组的所有数中统计在区间[1, y - 1]的数字的出现次数Lower[i] = ask(y - 1); //在前面已加入树状数组的所有数中统计在区间[y + 1, n]的数字的出现次数Greater[i] = ask(n) - ask(y);//将y加入树状数组,即数字y出现1次add(y, 1);}//清空树状数组,从右往左统计每个位置右边比第i个数y小的数的个数、以及大的数的个数memset(t, 0, sizeof t);LL resA = 0, resV = 0;//从右往左统计for(int i = n; i >= 1; i--){int y = a[i];resA += (LL)Lower[i] * ask(y - 1);resV += (LL)Greater[i] * (ask(n) - ask(y));//将y加入树状数组,即数字y出现1次add(y, 1);}printf("%lld %lld\n", resV, resA);return 0;
}

2.一个简单的整数问题:

给定长度为 N 的数列 A,然后输入 M 行操作指令。

第一类指令形如 C l r d,表示把数列中第 l∼r个数都加 d。

第二类指令形如 Q x,表示询问数列中第 x个数的值。

对于每个询问,输出一个整数表示答案。

输入格式

第一行包含两个整数 N 和 M。

第二行包含 N个整数 A[i]。

接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

1≤N,M≤1e5
|d|≤10000
|A[i]|≤1e9

输入样例:

10 5
1 2 3 4 5 6 7 8 9 10
Q 4
Q 1
Q 2
C 1 6 3
Q 2

输出样例:

4
1
2
5

思路:这是一个区间修改单点查询问题,构造一个差分数组,单点查询转换成区间前缀求和;

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&-x
#define int long long
const int N=2e5+10;
int n,m;
int a[N],tr[N];void add(int x,int c){for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;}
int sum(int x){int res=0;for(int i=x;i;i-=lowbit(i)) res+=tr[i];return res;
}signed main(){cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) add(i,a[i]-a[i-1]);while(m--){char op;cin>>op;if(op=='Q'){int x;cin>>x;cout<<sum(x)<<endl;}else {int l,r;int c;cin>>l>>r>>c;add(l,c),add(r+1,-c);}}return 0;
}

3.一个简单的整数问题2:

给定一个长度为 NN 的数列 AA,以及 MM 条指令,每条指令可能是以下两种之一:

  1. C l r d,表示把 A[l],A[l+1],…,A[r]都加上 d。
  2. Q l r,表示询问数列中第 l∼r个数的和。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数 N,M。

第二行 N 个整数 A[i]。

接下来 M 行表示 M条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

1≤N,M≤1e5,
|d|≤10000,
|A[i]|≤1e9

输入样例:

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

输出样例:

4
55
9
15

基本思路就是推公式,思路确实精巧。

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;const int N = 1e5 + 10;
int n, m;
int a[N];
LL tr[N], tri[N];
//tr[]数组是原始数组的差分数组d[i]的树状数组
//tri[]数组是原始数组的差分数组乘以i即i*d[i]的树状数组int lowbit(int x)
{return x & -x;
}
void add(LL c[], int x, int v)
{for (int i = x; i <= n; i += lowbit(i))c[i] += v;
}
LL query(LL c[], int x)
{LL res = 0;for (int i = x; i; i -= lowbit(i))res += c[i];return res;
}
//对应最后一步推导的公式
LL get_sum(int x)
{return query(tr, x) * (x + 1) - query(tri, x);
}
int main()
{scanf("%d%d", &n, &m);//输入数组a[i]for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);//先构造两个数组 d[i] 和 i*d[i]for (int i = 1; i <= n; ++i) tr[i] = a[i] - a[i - 1], tri[i] = tr[i] * i;//原地 O(n) 建树状数组for (int x = 1; x <= n; ++x)for (int i = x - 1; i >= x - lowbit(x) + 1; i -= lowbit(i))tr[x] += tr[i], tri[x] += tri[i];//读入查询while (m--){char op[2];int l, r, c;scanf("%s", op);if (op[0] == 'Q'){scanf("%d%d", &l, &r);printf("%lld\n", get_sum(r) - get_sum(l - 1));}else{scanf("%d%d%d", &l, &r, &c);add(tr, l, c), add(tr, r + 1, -c);add(tri, l, l * c), add(tri, r + 1, (r + 1) * -c);}}return 0;
}

树型结构——树状数组相关推荐

  1. mysql 转成树_Mysql树型结构2种方式及相互转换

    Mysql实现树型结构,数据库上常见有2种方式:领接表.预排序遍历树(MPTT). 领接表方式-- 主要依赖于一个 parent 字段,用于指向上级节点,将相邻的上下级节点连接起来,id 为自动递增自 ...

  2. 【唠叨两句】如何将一张树型结构的Excel表格中的数据导入到多张数据库表中...

    小弟昨天遇到一个相对比较棘手的问题,就像标题说的那样.如何将一张树型结构的Excel表格中的数据导入到多张数据库表中,在现实中实际是七张数据库表,这七张表之间有着有着相对比较复杂的主外键关系,对于我这 ...

  3. Linux TC 流量控制与排队规则 qdisc 树型结构详解(以HTB和RED为例)

    1. 背景 Linux 操作系统中的流量控制器 TC (Traffic Control) 用于Linux内核的流量控制,它规定建立处理数据包的队列,并定义队列中的数据包被发送的方式,从而实现对流量的控 ...

  4. 树型结构(数据结构)

    6.1树的基本概念 树型结构是区别于线性结构的另一大数据结构,它具有分支性和层次性. 树是由n(n>=0)个结点构成的有限集合.n=0的树称为空树:当n!=0时,树中的结点度应该满足下列条件: ...

  5. dtree和jquery构建树型结构

    对于小型的树型应用来说,dtree是一个不错的选择. 先看一眼dtree给的例子 构造静态树 首先引入css文件和js文件 <link rel="StyleSheet" hr ...

  6. EF架构~单表一对多集合的插入(树型结构)

    单表一对多关系很常见,它是一种树形结构,如系统菜单表,部门表,分类表,这些都可以做成单表一对多关系,而这些表做成一对多关系后,如果通过EntityFramework进行插入操作时,会很方便,EF会自动 ...

  7. C#实现树型结构TreeView节点拖拽的简单功能,附全部源码,供有需要的参考

    为什么80%的码农都做不了架构师?>>>    应用软件是否好用就体现在一些细节操作上,开发人员是否考虑到了很多细节,例如一个树形结构的数据若不支持拖拽功能那用起来会很糟糕一些,用户 ...

  8. go之树型结构深度理解补充

    go之树型结构深度理解补充 在上一篇中借用了 Ilija Eftimov 文章来讲解了tree的定义和一些方法.这篇文章主要是讲解在树型结构中如何判断节点与节点之间的关系. A节点是否是B节点的直接上 ...

  9. Nestable 可移动拖拽的树型结构的使用(jQuery)

    利用jQuery可以制作出很好的树型结构.这里介绍一款最近才找到使用的Nestable 可以拖动.  网页中的效果 http://dbushell.github.com/Nestable/ 具体详细介 ...

最新文章

  1. 使用Pyhthon,OpenCV和ZBar构建移动的条码扫描器
  2. 数学界的隐士:世界上最奇怪的数学天才,被奖励100万却拒领
  3. javascript es6 特性简介
  4. linux内核(4.17.10)配置项详解(x86)
  5. PHP和ajax详解
  6. oracle 判断是否位汉字,js判断字符是否是汉字的两种方法小结
  7. 怎样在电脑上上传图片_电脑上回收站怎样恢复
  8. [古诗十九首] 西北有高楼 —— 无名氏
  9. html5的常用标签,HTML5常用标签
  10. nor flash与nand flash启动的简单比较--APPLE的ARM学习笔记一
  11. 安装配置NTP服务器
  12. 王者荣耀钓鱼网源码php,王者荣耀钓鱼页面
  13. 四级网络工程师试题一
  14. 计算机网络组建校园网课设报告,计算机网络课设校园网组建.doc
  15. 利用jink的驱动软件j-flash 合并两个hex的方法,bootloader+app
  16. 以太网未识别的网络win10_win10以太网为什么无Internet未识别网络?
  17. Flutter高德定位定位权限管理
  18. 亚信大数据平台产品经理 杨晋:大数据是怎么应用于技术方面的
  19. 看似不负责任的菩提祖师,却用另外一种方式,造就了孙悟空的人生
  20. kestrel虚拟服务器,如何使Kestrel Web服务器监听非本地主机的请求?

热门文章

  1. icloud连接服务器时出现问题_iCloud服务器连接超时怎么办 试试这个解决方法
  2. 世界上最权威的管理名言
  3. HTML innerText
  4. [Android]视图的控触操作-MotionEvent
  5. 2021-02-06 SONiC SAI结构 AdapterAdapter Host
  6. 叫“哥”叫“姐”等于赶客,这样称呼回头率暴增!
  7. java的继承及其抽象方法
  8. Linux下ll 命令显示的文件类型
  9. 什么牌子投影仪好?投影仪买什么牌子的好
  10. VMware虚拟机Linux 两边出现黑屏幕的妙计解决方法。