YbtOJ 「数据结构」 第3章 RMQ问题
st表
A. 【例题1】数列区间
静态区间最值常用算法 设置
预处理
查询
+1和-1都要分清
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
const int N = 2e5 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , lg[N] = {-1} , st[N][31];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
for ( int i = 1 ; i <= n ; i ++ ) st[i][0] = read();
for ( int j = 1 ; j <= lg[n] ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
st[i][j] = max ( st[i][j-1] , st[i+(1<<(j-1))][j-1] );
for ( int i = 1 ; i <= m ; i ++ )
{
int l = read() , r = read();
int k = lg[r-l+1];
cout << max ( st[l][k] , st[r-(1<<k)+1][k] ) << endl;
}
return 0;
}
B. 【例题2】静态区间
维护的时候直接将求最大值改成求gcd 只是一个轻易的优化
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
const int N = 2e5 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , lg[N] = {-1} , st[N][31];
int gcd ( int a , int b )
{
if ( a % b == 0 ) return b;
return gcd ( b % a , a );
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
for ( int i = 1 ; i <= n ; i ++ ) st[i][0] = read();
for ( int j = 1 ; j <= lg[n] ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
st[i][j] = gcd ( st[i][j-1] , st[i+(1<<(j-1))][j-1] );
for ( int i = 1 ; i <= m ; i ++ )
{
int l = read() , r = read() , k = lg[r-l+1];
cout << gcd ( st[l][k] , st[r-(1<<k)+1][k] ) << endl;
}
return 0;
}
C. 【例题3】与众不同
[题目描述]
A 是某公司的 CEO,每个月都会有员工把公司的盈利数据送给 A,A 是个与众不同的怪人,A 不注重盈利还是亏本,而是喜欢研究「完美序列」:一段连续的序列满足序列中的数互不相同。
A 想知道区间
[输入格式]
第一行两个整数
第二行
接下来
[输出格式]
输出
[算法分析]
要么是标程错了 要么是评测机寄了 要么就是
下面放的代码是样例死循环但是
采用复制调试法后得到是初始化
进入正题 思路搞明白就可以了
我们记录三个数组:
表示以 为结尾的最长完美序列的长度 表示以 为结尾的完美序列的起始位置 表示上一个 的位置
可以在
查询:
假设我们要找
那么此时区间
这样就把区间分成了两部分 那么答案就是
[代码实现]
#include <bits/stdc++.h>
using namespace std;
#define inl inline
#define endl '\n'
#define mid ((l+r)>>1)
const int N = 2e6 + 10;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , a[N] , lg[N] , st[N][30] , last[N] , f[N] , pre[N];
int query ( int l , int r )
{
int k = lg[r-l+1];
return max ( st[l][k] , st[r-(1<<k)+1][k] );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
lg[0] = -1;
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
for ( int i = 1 ; i <= n ; i ++ )
{
a[i] = read();
pre[i] = max ( pre[i-1] , last[a[i]] + 1 );
last[a[i]] = i;
f[i] = i - pre[i] + 1;
st[i][0] = f[i];
}
for ( int j = 1 ; j <= lg[n] ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
st[i][j] = max ( st[i][j-1] , st[i+(1<<(j-1))][j-1] );
for ( int i = 1 , x , y , l , r ; i <= m ; i ++ )
{
l = x = read() + 1 , r = y = read() + 1;
while ( l <= r )
{
if ( pre[mid] < x ) l = mid + 1;
else r = mid - 1;
}
cout << max ( l - x , query ( l , y ) ) << endl;
}
return 0;
}
较为完备的代码(实际上应该在初始读入的时候整体权值+K避免负数下标 不过出题人都这样
#include <bits/stdc++.h>
using namespace std;
#define inl inline
#define endl '\n'
#define mid ((l+r)>>1)
#define int long long
const int N = 2e6 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , a[N] , lg[N] , st[N][20] , last[N] , f[N] , pre[N];
int query ( int l , int r )
{
int k = lg[r-l+1];
return max ( st[l][k] , st[r-(1<<k)+1][k] );
}
signed main ()
{
lg[0]=-1;
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
for ( int i = 1 ; i <= n ; i ++ )
{
a[i] = read();
pre[i] = max ( pre[i-1] , last[a[i]] + 1 );
last[a[i]] = i;
f[i] = i - pre[i] + 1;
st[i][0] = f[i];
}
for ( int j = 1 ; j <= lg[n] ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
st[i][j] = max ( st[i][j-1] , st[i+(1<<(j-1))][j-1] );
for ( int i = 1 , x , y , l , r ; i <= m ; i ++ )
{
l = x = read() + 1 , r = y = read() + 1;
if ( pre[y] <= x ) { cout << y - x + 1 << endl; continue; }
while ( l <= r )
{
if ( pre[mid] < x ) l = mid + 1;
else r = mid - 1;
}
cout << max ( ( l - 1 ) - x + 1 , query ( l , y ) ) << endl;
}
return 0;
}
D. 【例题4】矩阵最值
[题目描述]
我们有一个
[输入格式]
第一行三个整数
接下来
接下来
[输出格式]
共
[代码实现]
注意这里的
#include <bits/stdc++.h>
using namespace std;
#define inl inline
const int N = 255;
inl int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar (); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar (); }
return x * f;
}
int n , m , K , lg[N] , st[N][N][20][20];
int query ( int x11 , int y11 , int x22 , int y22 )
{
int lx = lg[x22-x11+1] , ly = lg[y22-y11+1];
return max ( max ( st[x11][y11][lx][ly] , st[x11][y22-(1<<ly)+1][lx][ly] ) , max ( st[x22-(1<<lx)+1][y11][lx][ly] , st[x22-(1<<lx)+1][y22-(1<<ly)+1][lx][ly] ) );
}
signed main ()
{
//freopen ( "a.in" , "r" , stdin );
lg[0] = -1;
n = read() , m = read() , K = read();
for ( int i = 1 ; i <= max ( n , m ) ; i ++ ) lg[i] = lg[i>>1] + 1;
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= m ; j ++ )
st[i][j][0][0] = read();
for ( int k = 0 ; k <= lg[n] ; k ++ )
for ( int l = 0 ; l <= lg[m] ; l ++ )
for ( int i = 1 ; i + ( 1 << k ) - 1 <= n ; i ++ )
for ( int j = 1 ; j + ( 1 << l ) - 1 <= m ; j ++ )
{
if ( k ) st[i][j][k][l] = max ( st[i][j][k][l] , max ( st[i][j][k-1][l] , st[i+(1<<(k-1))][j][k-1][l] ) );
if ( l ) st[i][j][k][l] = max ( st[i][j][k][l] , max ( st[i][j][k][l-1] , st[i][j+(1<<(l-1))][k][l-1] ) );
}
for ( int i = 1 , x11 , y11 , x22 , y22 ; i <= K ; i ++ )
{
x11 = read() , y11 = read() , x22 = read() , y22 = read();
printf ( "%d\n" , query ( x11 , y11 , x22 , y22 ) );
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】