CF1707E Replace

CF1707E Replace

3500。

注意到 f(l,r)=i=lr1f(i,i+1)f(l,r)= \bigcup_{i=l}^{r-1}f(i,i+1),即可合并。

还有,若 [l1,r1][l1,r1][l2,r2][l2,r2] 有交,则 f(l1,r1)f(l1,r1)f(l2,r2)f(l2,r2) 可合并也有交。

考虑用某种数据结构维护从某个区间跳若干次到的区间,由于可并,可以倍增跳。

可是倍增还需维护双向跳,一向是区间,一向是次数,上述只证一级可并,还需证明 kk 级可并,即 fk(l,r)=i=lr1fk(i,i+1)f^k(l,r)= \bigcup_{i=l}^{r-1}f^k(i,i+1)

证明:

上面证明了若 [l1,r1],[l2,r2][l1,r1],[l2,r2] 有交,则 f(l1,r1),f(l2,r2)f(l1,r1),f(l2,r2) 有交,进一步有 fk(l1,r1),fk(l2,r2)f^k(l1,r1),f^k(l2,r2) 有交可合并。

现合并无法快速求出。

显然,若 [l1,r1],[l2,r2][l1,r1],[l2,r2] 有交,则 f(l1,r1)f(l2,r2)=f(min(l1,l2),max(r1,r2))f(l1,r1) \cup f(l2,r2)=f(\min(l1,l2),\max(r1,r2))

证明完了,倍增预处理 f2k(l,r)f^{2^k}(l,r) 即可。

时间复杂度 O(nlog2n+mlogn)\mathcal O(n\log^2 n+m\log n)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define ha putchar(' ')
#define he putchar('\n')

inline int read() {
	int x = 0;
	char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}

inline void write(ll x) {
	if (x < 0)
		x = -x, putchar('-');
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + 48);
}

const int _ = 1e5 + 10;

int n, m, a[_], lg[_];

struct Node {
	int l, r;
	Node operator + (Node b) {
		return {min(l, b.l), max(r, b.r)};
	}
	bool ok() {
		return l == 1 && r == n;
	}
} f[35][17][_];

Node mge(int k, int l, int r) {
	if (l >= r) return {n, 1};
	int t = lg[r - l];
	return f[k][t][l] + f[k][t][r - (1 << t)];
}

ll qry(int l, int r) {
	if (l == 1 && r == n) return 0;
	if (!mge(34, l, r).ok()) return -1;
	ll res = 0;
	for (int i = 33; i >= 0; --i) {
		Node tmp = mge(i, l, r);
		if (!tmp.ok()) l = tmp.l, r = tmp.r, res |= (1ll << i);
	}
	return res + 1;
}

signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
	for (int k = 0; k <= 34; ++k) {
		if (!k)
			for (int i = 1; i < n; ++i)
				f[k][0][i] = {min(a[i], a[i + 1]), max(a[i], a[i + 1])};
		else
			for (int i = 1; i < n; ++i)
				f[k][0][i] = mge(k - 1, f[k - 1][0][i].l, f[k - 1][0][i].r);
		for (int j = 1; j <= 16; ++j)
			for (int i = 1; i + (1 << j) <= n; ++i)
				f[k][j][i] = f[k][j - 1][i] + f[k][j - 1][i + (1 << (j - 1))];
	}
	int l, r;
	while (m--) {
		l = read(), r = read();
		write(qry(l, r)), he;
	}
	return 0;
}
posted @ 2022-08-21 11:20  蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  来源