RMQ问题
RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。
主要方法(线段树,ST表,LCA)
1.线段树
支持修改,时间复杂度:预处理O(n),查询O(log(n))
例:HDU1754
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
//定义
#define maxn 500007 //元素总个数
int Max[maxn<<2],Add[maxn<<2];//Max求最大值,Add为懒惰标记
int A[maxn],n,ANS;//存原数组数据下标[1,n]
//建树
//PushUp函数更新节点信息 ,这里是求最大值
void PushUp(int rt){Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);}
//Build函数建树
void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号
if(l==r) {//若到达叶节点
Max[rt]=A[l];//储存数组值
return;
}
int m=(l+r)>>1;
//左右递归
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
//更新信息
PushUp(rt);
}
//点修改
void Update(int L,int C,int l,int r,int rt){//l,r表示当前节点区间,rt表示当前节点编号
if(l==r){//到叶节点,修改
Max[rt]=C;
return;
}
int m=(l+r)>>1;
//根据条件判断往左子树调用还是往右
if(L <= m) Update(L,C,l,m,rt<<1);
else Update(L,C,m+1,r,rt<<1|1);
PushUp(rt);//子节点更新了,所以本节点也需要更新信息
}
//区间查询
int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){
//在区间内,直接返回
return ANS=max(Max[rt],ANS);
}
int m=(l+r)>>1;
//累计答案
if(L <= m) Query(L,R,l,m,rt<<1);
if(R > m) Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
int main()
{
int m,u,v;
while(cin>>n>>m)
{
memset(Max,0,sizeof(Max));
memset(Add,0,sizeof(Add));
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
}
Build(1,n,1);
string str;
for(int i=1;i<=m;i++)
{
cin>>str;
if(str[0]=='Q')
{
ANS=0;
scanf("%d%d",&u,&v);
printf("%d
",Query(u,v,1,n,1));
}
else if(str[0]=='U')
{
scanf("%d%d",&u,&v);
Update(u,v,1,n,1);
}
}
}
}
2.ST表
以倍增思想为基础,不能在线修改,适合离线RMQ问题
时间复杂度: 预处理O(nlog(n)) 查询O(1)
预处理:先开辟一个数组(f[i][j])表示从第i号节点到第i+2j-1号节点的最大值,即从i号节点开始往后数共2j个节点中的最大值。
查询:查询x,y之间的最大值,记len为[x,y]区间长度 ,最大值=max((f[x][log {len}],f[y-2^{log{len}}+1][log{len}]))
具体思路参考这篇博客
例:洛谷p3865
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int a[110000][30],logg[110000],bin[110000];
int i,j,k,m,n,o,p,js,jl,x,y,t,lg;
int my_max(int x,int y)
{
if(x>y)return(x);
else return(y);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i][0]);
bin[0]=1;for(int i=1;i<=30;i++)bin[i]=bin[i-1]*2;
logg[0]=-1;for(int i=1;i<=n;i++)logg[i]=logg[i/2]+1;
for(int i=1;i<=logg[n];i++)
for(int j=1;j<=n;j++)
{
if(j+bin[i]-1<=n)
{
a[j][i]=my_max(a[j][i-1],a[j+bin[i-1]][i-1]);
}
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
t=y-x+1;lg=logg[t];
printf("%d
",my_max(a[x][lg],a[y-bin[lg]+1][lg]));
}
return 0;
}
3.LCA
太菜了,还不会....以后再写