st表是一种能够很好地完成一种特定的RMQ(区间最值问题)的算法。
为何说是特定的呢?
她只能解决一些不含修改操作的RMQ。
因为她的局限性比较大,所以她的时间复杂度很优秀(不然选她干嘛)。
预处理: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
每次询问一段区间的最值:是 O ( 1 ) O(1) O(1)的!!!
以这道题为例:
代码(核心部分):
for(rg int j = 1; (1 << j) <= N; j++)
for(rg int i = 1; i + (1 << j) - 1 <= N; i++)
st[i][j] = Max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
//初始化
while(M--) {
int x = read(), y = read();
int len = lg[y - x + 1];
writeln(Max(st[x][len], st[y - (1 << len) + 1][len]));
}
//询问
其中st数组意义为:
st[i][j]
从 i i i开始的 2 j 2^j 2j个数的最值
lg就是以2为底的对数(向下取整)
这就采用了一种倍增的想法。
奈斯!
tips:
这里的lg数组怎么求呢
用
里的log2
函数固然可以,但是效率很低,我们可以采用递推的方法。
lg[0] = -1;//必不可少!!!
for(rg int i = 1; i <= N; i++) lg[i] = lg[i / 2] + 1;
#define USEFASTERREAD 1
#define rg register
#define inl inline
#define DEBUG printf("qwq\n")
#define DEBUGd(x) printf("var %s is %lld", #x, ll(x))
#define DEBUGf(x) printf("var %s is %llf", #x, double(x))
#define putln putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
typedef unsigned long long ull;
#include
#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
inl void RS() {freopen("test.in", "r", stdin), freopen("test.out", "w", stdout);}
inl ll read() {
ll x = 0, f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
return x * f;
}
inl void write(ll x) {
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inl void writeln(ll x) {write(x), putln;}
inl void writesp(ll x) {write(x), putsp;}
}
using namespace IO;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
template<typename T> inline T Abs(const T& x) {return x < 0 ? -x : x;}
const int MAXLEN = 20;
const int MAXN = 1e5 + 5;
int N, M;
int st[MAXN][MAXLEN];
int lg[MAXN];
int main() {
//RS();
N = read(); M = read();
lg[0] = -1;
for(rg int i = 1; i <= N; i++) lg[i] = lg[i / 2] + 1;
for(rg int i = 1; i <= N; i++) st[i][0] = read();
for(rg int j = 1; (1 << j) <= N; j++)
for(rg int i = 1; i + (1 << j) - 1 <= N; i++)
st[i][j] = Max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
while(M--) {
int x = read(), y = read();
int len = lg[y - x + 1];
writeln(Max(st[x][len], st[y - (1 << len) + 1][len]));
}
return 0;
}
一道和T1差不多的水题2333
直接放代码把,不讲啦
#define USEFASTERREAD 1
#define rg register
#define inl inline
#define DEBUG printf("qwq\n")
#define DEBUGd(x) printf("var %s is %lld", #x, ll(x))
#define DEBUGf(x) printf("var %s is %llf", #x, double(x))
#define putln putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
typedef unsigned long long ull;
#include
#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
inl void RS() {freopen("test.in", "r", stdin), freopen("test.out", "w", stdout);}
inl ll read() {
ll x = 0, f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
return x * f;
}
inl void write(ll x) {
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inl void writeln(ll x) {write(x), putln;}
inl void writesp(ll x) {write(x), putsp;}
}
using namespace IO;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
template<typename T> inline T Abs(const T& x) {return x < 0 ? -x : x;}
const int MAXN = 1e5 + 5;
const int MAXLEN = 20;
int n, k;
int Mx[MAXN][MAXLEN];
int Mn[MAXN][MAXLEN];
int lg[MAXN];
int askMx(int l, int r) {
int len = lg[r - l + 1];
return Max(Mx[l][len], Mx[r - (1 << len) + 1][len]);
}
int askMn(int l, int r) {
int len = lg[r - l + 1];
return Min(Mn[l][len], Mn[r - (1 << len) + 1][len]);
}
int main() {
//RS();
n = read(), k = read();
lg[0] = -1;
for(rg int i = 1; i <= n; i++) lg[i] = lg[i / 2] + 1;
for(rg int i = 1; i <= n; i++) Mx[i][0] = Mn[i][0] = read();
for(rg int j = 1; (1 << j) <= n; j++)
for(rg int i = 1; i + (1 << j) - 1 <= n; i++) {
Mx[i][j] = Max(Mx[i][j - 1], Mx[i + (1 << (j - 1))][j - 1]);
Mn[i][j] = Min(Mn[i][j - 1], Mn[i + (1 << (j - 1))][j - 1]);
}
for(rg int i = 1; i <= n - k + 1; i++) {
writesp(askMx(i, i + k - 1)), writeln(askMn(i, i + k - 1));
}
return 0;
}
时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
这道题能不能优化成 O ( n ) O(n) O(n)呢?
这道题看起来怎么这么像滑动窗口呢?
对,我们可以写单调队列啊!!!
#define USEFASTERREAD 1
#define rg register
#define inl inline
#define DEBUG printf("qwq\n")
#define DEBUGd(x) printf("var %s is %lld", #x, ll(x))
#define DEBUGf(x) printf("var %s is %llf", #x, double(x))
#define putln putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
typedef unsigned long long ull;
#include
#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
inl void RS() {freopen("test.in", "r", stdin), freopen("test.out", "w", stdout);}
inl ll read() {
ll x = 0, f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
return x * f;
}
inl void write(ll x) {
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inl void writeln(ll x) {write(x), putln;}
inl void writesp(ll x) {write(x), putsp;}
}
using namespace IO;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
template<typename T> inline T Abs(const T& x) {return x < 0 ? -x : x;}
#include
using std::deque;
const int MAXN = 1e5 + 5;
int n, k;
int a[MAXN];
deque<int> Mn;
deque<int> Mx;
int main() {
//RS();
n = read();
k = read();
for(rg int i = 1; i <= n; i++) a[i] = read();
for(rg int i = 1; i <= n; i++) {
while(!Mx.empty() && a[Mx.back()] <= a[i]) Mx.pop_back();
Mx.push_back(i);
while(!Mx.empty() && i - Mx.front() + 1 > k) Mx.pop_front();
while(!Mn.empty() && a[Mn.back()] >= a[i]) Mn.pop_back();
Mn.push_back(i);
while(!Mn.empty() && i - Mn.front() + 1 > k) Mn.pop_front();
if(i >= k) {
writesp(a[Mx.front()]), writeln(a[Mn.front()]);
}
}
return 0;
}
岂不美哉~