标签:scan int 问题 现在 左移 最大 end 为什么 []
st表--目的是解决RMQ问题(多次询问区间最值)
既然叫‘表’,那肯定要打个表,然后你问什么,我就在表里找就可以了,这样,询问时的时间复杂度就是O(n)。
妈妈再也不用担心我会超时了
设你把一个需要处理的序列存储在a [ i ] 中
s tiao表,首先要声明一个二维数组jump[i][j] or tiao[i][j] 来存储序列的最值(这里以最大值为例)
然后,定义(你心里明白就好)
jump[ i ][ j ] 表示区间 [ i , i + (2 ^ j) - 1 ] 的最值
不要问为什么,后面你会明白的。
然后把 jump[ i ][ j ]分开
jump[ i ][ j ] = max( jump [ i ][ j-1 ] , jump[ i + ( 2 ^ (j-1) ][ j - 1 ] )
max中前者为 [ i , i + ( 2 ^ (j-1) ) - 1 ]
后者为 [ i + ( 2 ^ (j-1) , i + ( 2 ^ j ) ]
刚好把 jump[ i ][ j ] 分开。所以最大值一定在其中。
jump[ i ][ 0 ]max = a[ i ]这是显然的,
所以就不需要前文中提到的 a [ i ] 了。
我们可以直接把数字序列存储到 jump[ i ][ 0 ] 中。
然后根据
jump[ i ][ j ] = max( jump [ i ][ j-1 ] , jump[ i + ( 2 ^ (j-1) ][ j - 1 ] )
把表打出来
对于一个要询问的区间[ x , y ]
找一个 k ,使得 k <= y - x + 1 < 2 * k
这里我们取 k = log2( y - x + 1 )
那么,我们就把区间 [ x , y ] 的最大值就表示为
max( jump[ x ][ k ] , jump[ y - ( ( 2 ^ k ) -1 ) ][ k ] )
其实就是区间 [ x , x + ( 2 ^ k ) - 1 ]
和区间 [ y - ( ( 2 ^ k ) - 1 ) , y ]
x + ( 2 ^ k ) - 1 是大于等于 y - ( ( 2 ^ k ) - 1 ) 的
及两个区间相交,那么[ x , y ] 的最大值就一定在这两个区间之中。
先把题链过来
接下来是代码
//This is Tao‘s program;
#include<bits/stdc++.h>
using namespace std;
//返回一个最大值
int max(int x,int y)
{
if(x>y) return x;
return y;
}
//存储 st 表的数组
int jump[500004][20];
int main()
{
//l,r为稍候询问时输入的查询的区间[l,r]
//k为log2(r-l+1),取的是一个‘中间‘的值
int n(0),m(0),l(0),r(0),k(0);
//输入数列长度n,询问的个数m
scanf("%d%d",&n,&m);
//输入数列,存储至 jump[i][0]中
for(int i = 0;i<n;++i)
{
scanf("%d",&jump[i][0]);
}
//打st表,存储至 jump[][] 数组中
//jump[i][j] 表示区间 [i , i+(2^j)-1]
//1<<j就表示 2^j
for(int j = 1;j<=20;++j)
{
for(int i = 0;i+(1<<j)-1<n;++i)
{
jump[i][j] = max(jump[i][j-1],jump[i+(1<<(j-1))][j-1]);
}
}
//现在开始RMQ
for(int i = 1;i<=m;++i)
{
scanf("%d%d",&l,&r);
--l;--r; //由于之前打的表是从 jump[0][0] 开始的,而读入时是从1开始的
//故整个往左移1位
k = log2(r-l+1);//取一个‘中间值‘k
//区间 [l , l+(2^k)-1]和[r-((2^k)-1) , r]有相交部分
//故最大值必定在这两个区间之中
int s = max(jump[l][k],jump[r-(1<<k)+1][k]);
printf("%d\n",s); //输出s
}
return 0;
}
end
标签:scan int 问题 现在 左移 最大 end 为什么 []
原文地址:https://www.cnblogs.com/taorex/p/10294922.html