「
「
「数据结构
」
」
」第
3
3
3章
R
M
Q
RMQ
RMQ问题
(
(
(前
2
2
2题
)
)
)
目录:
A.数列区间
B.静态区间
A . A. A. 例题 1 1 1 数列区间
分析:
s
t
st
st表 一般用于解决这种
R
M
Q
RMQ
RMQ问题
(
(
(区间最值
)
)
)
之前写的讲的不是很清楚
l
i
n
k
link
link
s
t
st
st表是倍增的思想
如果
f
i
,
j
f_{i,j}
fi,j 表示从
i
i
i位置开始
2
j
2^j
2j个数的最大值 如
f
i
,
1
f_{i,1}
fi,1 就是指
f
i
f_i
fi
f
i
+
1
f_{i+1}
fi+1的最大值
那么转移的时候 就直接把当前区间 拆分成两个区间 分别取
m
a
x
max
max
要先得出
l
o
g
2
log2
log2区间
l
e
n
len
len 这样才能倍增
2
k
2^k
2k 然后在左端点和 右端点分别查询
右端点是
r
r
r 左端点是
r
−
2
k
+
1
r-2^k+1
r−2k+1 因为要找一个左端点
l
l
l 使
l
+
2
k
−
1
=
r
l+2^k-1=r
l+2k−1=r
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e6+10;
int a[N][21],n,m;
int query(int l,int r)
{
int k=log2(r-l+1); //处理log2的区间长度
return max(a[l][k],a[r-(1<<k)+1][k]); //找两区间最大
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i][0]=x; //i开始的2^0个数 的最大就是自己
}
for(int j=1;j<=21;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
a[i][j]=max(a[i][j-1],a[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r));
}
return 0;
}
B . B. B. 例题 2 2 2 静态区间
分析:
其实就是取
m
a
x
max
max的
s
t
st
st表改一下 变成取
g
c
d
gcd
gcd就行了
d
p
dp
dp也可过 然后顺手写了个线段树(
ST表 CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=5e4+10;
int a[N][21],n,m;
int query(int l,int r)
{
int k=log2(r-l+1);
return __gcd(a[l][k],a[r-(1<<k)+1][k]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i][0]=x;
}
for(int j=1;j<=21;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
a[i][j]=__gcd(a[i][j-1],a[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r));
}
return 0;
}
线段树 CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=5e4+10;
int n,m,a[N];
void build(int x,int l,int r)
{
if(l==r)
{
scanf("%d",&a[x]);
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
a[x]=__gcd(a[x<<1],a[x<<1|1]);
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return a[x];
int res=0,mid=(l+r)>>1;
if(L<=mid) res+=query(x<<1,l,mid,L,R);
if(mid<R) res=__gcd(res,query(x<<1|1,mid+1,r,L,R));
return res;
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(1,1,n,l,r));
}
return 0;
}