CF1707E Replace
CF1707E Replace
3500。
注意到 ,即可合并。
还有,若 和 有交,则 和 可合并也有交。
考虑用某种数据结构维护从某个区间跳若干次到的区间,由于可并,可以倍增跳。
可是倍增还需维护双向跳,一向是区间,一向是次数,上述只证一级可并,还需证明 级可并,即 。
证明:
上面证明了若 有交,则 有交,进一步有 有交可合并。
现合并无法快速求出。
显然,若 有交,则 。
证明完了,倍增预处理 即可。
时间复杂度 。
#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;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121963