ST表

\(ST\)

1、定义与用途:一种用于快速查询区间 \(max,min,or,and,gcd\) 等等的算法,查询时间为 \(O(1)\),不过需要预处理,预处理时间为 \(nlogn\),且不支持区间修改和单点修改。

2、理解:\(ST\) 表主要是利用倍增数组来实现的,对于求解那些区间里面的数可以重复利用的问题,可以直接用 \(ST\) 表来实现,像求解区间 \(xor\) 就无法利用 \(ST\) 表来实现,因为如果重复利用区间里的数的话会导致区间内有些数产生两次贡献,导致值被抵消 \((x\ xor\ x) = 0\)

3、例题:LUOGU

(1)动态 \(ST\) 表数组:

int lg[N + 1];
void init() {
	for (int i = 2; i <= N; i++) {
		lg[i] = lg[i >> 1] + 1;
	}
}

template <typename T>
class St{
		using VT = vector<T>;
		using VVT = vector<VT>;
		using func_type = function<T(const T &, const T &)>;

		VVT ST;

		static T default_func(const T &t1, const T &t2) {
			return t1 & t2;
		}

		func_type op;

	public:
		St(const vector<T> &v, func_type _func = default_func) {
			op = _func;
			int len = v.size(), l1 = ceil(log2(len)) + 1;
			ST.assign(len, VT(l1, 0));
			for (int i = 0; i < len; ++i) {
				ST[i][0] = v[i];
			}
			for (int j = 1; j < l1; ++j) {
				int pj = (1 << (j - 1));
				for (int i = 0; i + pj < len; ++i) {
					ST[i][j] = op(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
				}
			}
		}

		T query(int l, int r) {
			if (l == r) {
				return ST[l][0];
			}
			int lt = r - l + 1;
			int q = lg[lt];
			return op(ST[l][q], ST[r - (1 << q) + 1][q]);
		}
};

(2)静态 \(ST\) 表数组:

const int N = 1e6 + 5;
const int logN = 21;
i64 ST[N + 1][logN + 1];
i64 lg[N + 1], a[N + 1];

void init() {
	for (int i = 2; i <= N; i++) {
		lg[i] = lg[i >> 1] + 1;
	}
}

inline i64 max(i64 x, i64 y) {
	return (x > y ? x : y);
}

inline i64 min(i64 x, i64 y) {
	return (x < y ? x : y);
}

inline i64 o_r(i64 x, i64 y) {
	return (x or y);
}

inline i64 an_d(i64 x, i64 y) {
	return (x and y);
}

inline i64 gcd(i64 x, i64 y) {
	return (x % y == 0 ? y : gcd(y, x % y));
}

inline void st_deal(int n) {
	int len = ceil(log2(n));
	for (int i = 1; i <= n; i++) {
		ST[i][0] = a[i];
	}
	for (int le = 1; le <= len; le++) {
		int pj = 1 << (le - 1);
		for (int i = 1; i + pj <= n; i++) {
			ST[i][le] = max(ST[i][le - 1], ST[i + pj][le - 1]);
		}
	}
}

inline i64 query(int l, int r) {
	if (l == r) {
		return ST[l][0];
	}
	int lt = r - l + 1;
	int q = lg[lt];
	return max(ST[l][q], ST[r - (1 << q) + 1][q]);
}

注:为什么有动态的,还非要写个静态 \(ST\) 表呢,这是因为动态数组遇到数组长度较大的,会导致耗时更多,有时候会被卡掉,而静态数组就没有这种担忧,但是动态数组更方便,所以常用第一种写法。

posted @ 2024-08-15 01:55  grape_king  阅读(49)  评论(0)    收藏  举报