ST表(跳表)

倍增

  • 倍增是一种思想,也是一个算法
  • 倍增比二分的常数要大,但比二分更好写
int x=-1;
for(int i=31;~i;--i) if(pan(x+(1<<i)) x+=(1<<i);      // ~i的意思是i!=-1
  • 倍增在树上和链上更常见

ST表

跳表用于只需查询的问题中【把需要的信息预处理】
ST表又叫跳表
ST表有两种,一种是根号跳表,另一种是倍增跳表
跳表是为了处理静态查询问题,线段树既可以处理静态查询,也可以处理动态查询

区间长度为n【1e5的话】,查询m次
跳表相对于线段树的优势在于,其单次查询是O(1)的,线段树的查询是O(lgn)的【线段树查询可能跑不满 lg】
而相对而言,其预处理是O(nlgn)【lg跑满了】,线段树建树也是O(nlgn)【lg跑不满】
所以跳表在查询次数非常大时,才能发挥优势,否则直接上线段树吧
所以m<=n时,跳表不具优势,但 m=10N 时,倍增跳表时间优,m=100N 时,根号跳表时间更优【根号跳表比倍增跳表需要的空间要大】

st表的本质:st[i][j]表示以i为起点,长度为 j 的区间信息,其本质就是预处理区间信息(不需要后期维护)

根号跳表

根号跳表原理: 
n可以分解为sqrt(n)*sqrt(n) 
任何一个数x都可以写成 a*sqrt(n)+b  //a小于sqrt(n),b也小于sqrt(n) 

st_small[N][sqrt(N)]; //小表,st_sm[i][j]表示以i为起点,长度为j的区间最值   // j<=sqrt(n)
st_big[N][sqrt(N)]; //大表,st_big[i][j]表示以i为起点,长度为j*sqrt(n)的区间最值  //j<=sqrt(n)

int z=sqrt(n);
st_sm[i][1]=a[i];
st_sm[i][j]=max(st_sm[i][j-1],a[i+j-1]);

st_big[i][1]=st_sm[i][z];
st_big[i][j]=max(st_big[i][j-1],st_sm[i+(j-1)*z][z]);

int ask(int l,int r){
	int len=r-l+1;
	return max(st_big[l][len/z],st_sm[l+len/z*z][len-(len/z*z)]);   //也可以写成%,但为了好理解,写成减比较好 
}

#include<bits/stdc++.h>
using namespace std;
int const N=1e5+7;
int const L=3e2+7;
int n,m,bl;
int a[N];
int sts[N][L],stb[N][L];
int ask(int l,int r){
	int len=r-l+1;
	return max(stb[l][len/bl],sts[l+len/bl*bl][len-len/bl*bl]);  //
}
int main(){
	cin >> n >> m;
	for(int i=1;i<=n;++i) cin >> a[i];
	bl=ceil(sqrt(n));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=bl&&i+j-1<=n;++j){  //&&i+j-1<=n 为实际意义的限制,既可以防止数组越界,又可以优化时间常数  //以后这种情况都这么写(for有好几个限制时,把条件全部写出来),这么写不会错,不写还要考虑是否越界,还会增大时间常数
			if(j==1) sts[i][j]=a[i];
			else sts[i][j]=max(sts[i][j-1],a[i+j-1]);
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=bl&&i+j*bl-1<=n;++j){   //&&i+j*bl-1<=n   //j<=bl可以省略
			if(j==1) stb[i][j]=sts[i][bl];
			else stb[i][j]=max(stb[i][j-1],sts[i+(j-1)*bl][bl]);   //
		}
	}	
	int l,r;
	while(m--){
		cin >> l >> r;
		cout << ask(l,r) << "\n";
	}
	return 0;
}

倍增跳表

用于查询可重复合并的区间信息,比如 RMQ,GCD等等,也就是多次合并不影响结果
倍增跳表原理:
st[N][lg(N)];    //st[i][j]表示以i为起点,长度为2^j的区间最值

st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);

int ask(int l,int r){
    int k=log2(r-l+1);   //向下取整
    return max(st[l][k],st[r-(1<<k)][k]);
}

log2不要调用系统函数
众所周知,在处理整数问题上,pow,log,log2,sqrt等函数都比较有问题
第一是精度问题【它们是先转换成小数运算,再转换回整数】,第二是时间常数

预处理log2
如果范围不大,可以暴力预处理
LG2[1]=0;
for(int i=2;i<n;++i) LG2[i]=LG2[i/2]+1;   //因为对数【logx(y)】的实际意义就是y能除以x几次,与幂的定义【运算】相反,幂【x^y】是x乘y次的结果

扩展:
LGX[1]=0;
for(int i=2;i<n;++i) LGX[i]=LGX[y/x]+1;


#include<bits/stdc++.h>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 
#define ll long long
int const N=1e5+7;
int n,m;
int a[N];
int st[N][20];
void build(){
	for(int i=1;i<=n;++i) st[i][0]=a[i];
	for(int j=1;(1<<j)<=n;++j){
		for(int i=1;i<=n&&i+(1<<j)-1<=n;++i){  //i<=n可以省略 
			st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
		}
	}
}
int LG2[N];
void init(){
	LG2[1]=0;
	for(int i=2;i<=n;++i) LG2[i]=LG2[i/2]+1;   //这里的LG2是lg2向下取整 
}
int ask(int l,int r){
	int len=r-l+1;
	int k=LG2[len];
	return max(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
	fio;
	cin >> n >> m;
	for(int i=1;i<=n;++i) cin >> a[i];
	build();
	init();
	int l,r;
	while(m--){
		cin >> l >> r;
		cout << ask(l,r) << "\n";
	}
	return 0;
}



全部评论

相关推荐

05-09 14:45
门头沟学院 Java
点赞 评论 收藏
分享
迟缓的斜杠青年巴比Q了:简历被投过的公司卖出去了,我前两天遇到过更离谱的,打电话来问我有没有意向报班学Java学习,服了,还拿我学校一个学长在他们那报班学了之后干了华为OD当招牌
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
05-29 22:21
Offer1:小马智行,深圳,测试开发工程师,17.0k*16.0,Offer2:追觅科技,深圳,嵌入式工程师,18.0k*15.0,
嵌软狗都不学:各位base深圳的同事,作为也是并肩作战的一员,今天想站在管理视角,和大家开诚布公地聊一聊:从近几个月的上下班数据对比看来,我们发现一个明显的差异:深圳同事的在岗时间普遍比苏州同事短。很多深圳同事早上9点之后才到公司,晚上不到 20 点就下班了;而总部那边,20点半甚至 22 点后还有不少同事在办公室忙碌,特别是研发团队,加班更是常态。相信去过苏州的同事,对这种场景都不陌生。我很好奇,这是因为苏州工作任务太重还是咱们深圳同事效率真的高到能在更短时间内完成工作?MOVA在深圳成立分公司是为了吸引更优秀的人才贡献更多更高质的价值,公司管理层给我反馈的是深圳招到的多是行业的专家大拿,大部分都是薪资比苏州高的,而且我们办公的租金等也远高于苏州的..MOVA虽脱胎于强壮的集团母体不久,各业务板块尚未实现全面盈利,虽说公司管理层目光长远,不纠结当下的人才投入,但行业内的普遍标准是,员工创造的价值要达到公司雇佣成本的 15 倍以上。大家不妨自我审视一下,自己是否达到了这个标准?如果是抱着划水、按时打卡走人拿毛爷爷的心态那不适合来MOVA,那样过下去不但自己过得尴尬也会影响MOVA这个大船的攻城略地的速度.我并非鼓励大家盲目加班,而是倡导高效工作,拒绝无效忙碌,不要让项目进度因低效受影响,也别把精力浪费在和苏州同事拼打卡时长上,提倡更高的人效比;考虑到两地地域和交通差异,相信大家会找最适合自己发挥的工作方式(比如按时下班后1小时到家晚饭后继续未竟工作等..)大家在遵守公司规章的情况下尽情地体现自己的能力价值,为MOV!和深圳公司争光我们在这边才能更安心更有信心的工作下去;请客BU长、名部门长、项目管理和各业务单元负责人,全面梳理团队情况,及时评估成员工作负荷与成果质量,坚决清退划水害虫痕疫,践行公司价值观,相互监督,防止管理漏洞及渎职。感谢人家的理解,也请人家多担待我的直言不讳……
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务