ST表与树状数组
ST表
st表可以解决区间最值的问题。可以做到O(nlogn)预处理 ,O(1)查询,但是不支持修改。
st表的大概思路就是用st[i][j]来表示从i开始的2的j次方个树中的最值,查询时就从左端点开始,找到区间长度是2的多少次方,然后进行查询。然而,很明显,我们要查询的区间长度不一定是2的多少次幂。那怎么做到O(1)查询呢,这就要用到最值的特性。

如图,假如我们要查询2到7之间的最大值,但是7-2+1在22与23之间,我们选择22,也就是st[2][2],那剩下的6,7怎么办,我们考虑倒着从7往回算,也就是在st[7-22][2]与st[2][2]取max作为从2到7的最大值。
首先,进行预处理,st[i][j]表示从i开始的2的j次方,那么st[i][j]就应该是从i开始2的j-1次方与从i+2j-1开始的2的j-1次方中的最大值,那么进行递推就好了。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
const int N=;
int n,m,a[N],st[N][],log[N],cf[];
void pre()
{
log[]=;
log[]=;
for(int i=;i<=n;++i)
{
log[i]=log[i/]+;
}
cf[]=;
cf[]=;
for(int i=;i<=log[n]+;++i)
{
cf[i]=cf[i-]*;
}
}
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>'')
{
if(c=='-') f=-;
c=getchar();
}
while(c>=''&&c<='')
{
x=x*+c-'';
c=getchar();
}
return x;
}
int ff(int x,int y)
{
int l=y-x+,k=log[l];
int f=max(st[x][k],st[y-cf[k]+][k]);
return f;
}
int main()
{
n=read(),m=read();
pre();
for(int i=;i<=n;++i)
{
st[i][]=a[i]=read(); } for(int j=;j<=log[n];++j)
{
for(int i=;i+cf[j]-<=n;++i)
{
st[i][j]=max(st[i][j-],st[i+cf[j-]][j-]);
}
}
for(int i=,x,y;i<=m;++i)
{
x=read(),y=read();
cout<<ff(x,y)<<"\n";
}
return ;
}
树状数组
其实,树状数组的原理我并不是很懂,但是因为其短小精炼的代码,令我非常喜欢。。。。
树状数组不需要预处理,只有修改与查询两种操作。修改可以是加或减一个值,查询的是一个区间和。
首先我们需要一个数组tree。
然后就是修改,只需写一个几行的子函数,然后将修改元素的下标和要加的元素传入函数,然后奇迹就发生了。
查询传入要查询的下标就可以查询从1到改元素之间的区间和,如果查询从l到r,只需分别求出其从以到他们的区间和,然后相减即可,类似于前缀和。具体的都在代码里了。
#include<cstdio>
#include<iostream>
using namespace std;
const int N=;
int tree[N],n,m;
void add(int a,int pos)
{
while(pos<=n){
tree[pos]+=a;
pos+=pos&-pos;
}
}
int cc(int pos)
{
int ans=;
while(pos>=){
ans+=tree[pos];
pos-=pos&-pos;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x;i<=n;++i)
{
scanf("%d",&x);
add(x,i);
}
for(int i=,bz,x,y;i<=m;++i){
scanf("%d%d%d",&bz,&x,&y);
if(bz==)
add(y,x);
else{
int kk=cc(y),zz=cc(x-);
printf("%d\n",kk-zz);
}
}
return ;
}
上面讲的是树状数组的单点修改和区间查询,下面写一下,树状数组的区间修改单点查询。
首先介绍一下差分数组和前缀和。
前缀和就是记录前几个数的和,差分数组呢就是记录当前位置减去前一个位置的数的差。
然后要用到一个前缀和与差分数组的性质:前缀和数组的差分数组是原数组,差分数组的前缀和是原数组。
证明很显然,动手一推就知道了。
那么这与树状数组有什么关系呢,通过上面那个树状数组,我们知道,树状数组可以记录前几个数的和,现在我们要做的是区间修改和单点查询。
这时又要用到一个差分数组的一个性质。
差分数组进行区间加减时比较方便,比如如果将从i到j之间的数加k,那么只需将他们的差分数组i位置+k,并且将j+1位置的数-k即可。
证明同样很显然,动手推。
那么这就有联系了,我们树状数组维护的相当于是前缀和,然后我们如果用他维护原数组的差分数组,那么他就相当于维护的原数组,这样利用第一个性质单点查询就解决了。再就是区间修改,因为我们维护的是差分数组,所以利用性质二进行区间修改就好了。
看代码就很清楚明了了
#include<cstdio>
#include<iostream>
using namespace std;
const int N=;
int n,m,a[N],tree[N];
void read(int &x)
{
x=;int f=;char c=getchar();
while(c<''||c>'') { if(c=='-') f=-; c=getchar(); }
while(c>=''&&c<=''){ x=x*+c-''; c=getchar();}
x=x*f;
}
void add(int pos,int w)
{
while(pos<=n)
{
tree[pos]+=w;
pos+=pos&-pos;
}
return;
}
int ff(int pos)
{
int ans=;
while(pos>=)
{
ans+=tree[pos];
pos-=pos&-pos;
}
return ans;
} int main()
{
int last=;
read(n),read(m);
for(int i=,x;i<=n;++i)
{
read(x);
add(i,x-last);
last=x;
}
for(int i=,x,y,z,k;i<=m;++i)
{
read(x);
if(x==)
{
read(y),read(z),read(k);
add(y,k);
add(z+,-k);
}
else if(x==)
{
read(y);
printf("%d\n",ff(y));
}
}
return ;
}
ST表与树状数组的更多相关文章
- st表、树状数组与线段树 笔记与思路整理
已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...
- RMQ--树状数组,ST表,线段树
RMQ Range Minimum/Maximum Query 区间最值问题 树状数组 https://www.cnblogs.com/xenny/p/9739600.html lowbit(x) x ...
- st表树状数组入门题单
预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...
- uva11610 树状数组+素数打表求因子,好题!
/* uva11610 树状数组+素数打表+离散化 打出的素数范围在2-1000000之间,不超过六位数,然后按照格式翻转成七位数 */ #include<bits/stdc++.h> u ...
- 哈理工赛 H-小乐乐学数学 /// 筛法得素数表+树状数组
题目大意: 给定n个数 m个询问 询问l r区间内的孤独数的个数 孤独数的定义为在该区间内与其他所有数互质的数 看注释 #include <bits/stdc++.h> using nam ...
- bzoj 3730 震波——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 查询一个点可以转化为查询点分树上自己到根的路径上每个点对应范围答案.可用树状数组 f ...
- bzoj 3730 震波 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 建点分树,每个点记两个树状数组,存它作为重心管辖的范围内,所有点到它的距离情况和到它在 ...
- 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)
传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...
- (DP ST表 线段树)51NOD 1174 区间中最大的数
给出一个有N个数的序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,最大的数是多少. 例如: 1 7 6 3 1.i = 1, j = 3,对应的数为7 6 3,最大的数为7. ...
随机推荐
- C#_委托的使用
C#基础---委托的使用 一:什么是委托 委托是一种定义方法签名的类型当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联.您可以通过委托实例调用方法.委托是一个引用类型,所以它具 ...
- 利用Git工具将本地创建的项目上传到Github上
前言 作为一个对前沿技术很看好的小青年,怎么能不会用Github呢?一年前我创建了Github,也知道git,但是尝试过用,但是就没弄明白,很多粉丝都问我Github的账号,想关注一波,无奈里面啥都没 ...
- iphone忘记锁屏密码却记得appleID密码的不保存数据的刷机办法
请注意看清题目再看本文,另外一切后果博主不负任何责任.操作实现环境:原装数据线,拔掉sim卡昨天,iPhone6sp忘记密码被锁定,尝试通过找回手机抹除手机功能后,提示需要手机接入互联网才能实现,而我 ...
- uml 图学习记录
UML类图与类的关系详解 2011-04-21 来源:网络 在画类图的时候,理清类和类之间的关系是重点.类的关系有泛化(Generalization).实现(Realization).依赖(D ...
- win10装MySQL5.7
越来越发现装MySQL很费劲啊,装了N次,都很懵逼,找对的解决方案很重要. Mysql5.7下载地址:http://xiazai.zol.com.cn/detail/4/33431.shtml 安装步 ...
- BugPhobia进阶篇章:前端技术/设计文档
0x01 :前端概述 0x0100 :前端基本描述 前端基础框架 Semantic UI 根据http://semantic-ui.com/提供的样例和文档,依据Version 2.1.4版本的特性进 ...
- SQL Server 递归查询上级或下级组织数据(上下级数据通用查询语法)
查询上级组织数据: WITH OCTE AS ( AS LVL FROM IOV_Users U LEFT JOIN IOV_Organization O ON U.OrgId=O.ID UNION ...
- Activiti的BPMN演示工具
场景是这样的:产品经理不懂技术,又不想安装Java以及Eclipse(需要安装Activiti BPMN Designer的插件). 这两天解决.bpmn的解析(BPMNParser)时顺带找到一个顺 ...
- Character Encoding Issues for tomcat
https://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q8 https://stackoverflow.com/questions/10936846 ...
- 关于splice()方法,slice() 、split()方法讲解,reverse()方法、replace()方法
1.slice() 方法可从已有的数组中返回选定的元素. 语法 arrayObject.slice(start,end) 参数 描述 start 必需.规定从何处开始选取.如果是负数,那么它规定从数组 ...