ST表初步理解

文章目录

  • st表的作用
  • 代码(模板)
    • 例题引入
    • 详细代码
  • 第二道例题
    • 详细代码1
    • 优化(其实这与ST表无关)
    • 详细代码2

st表的作用

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

直接放代码把,不讲啦

详细代码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 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)

优化(其实这与ST表无关)

这道题能不能优化成 O ( n ) O(n) O(n)呢?
这道题看起来怎么这么像滑动窗口呢?
对,我们可以写单调队列啊!!!

详细代码2

#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;
}

岂不美哉~

你可能感兴趣的:(OI的那些事,OI,RMQ,ST表,题解,知识点)