CF765F 题解
namelessgugugu · · 题解
为什么大家都不写莫队!
题面
给定长度为
题解
考虑莫队,最暴力的朴素莫队必然是用 set 维护元素集合和相邻两个数的差的集合,复杂度
考虑到如果每次只插入一个数,我们只需要求出这个数的前驱和后继即可快速更新答案,于是不难想到使用回滚莫队和链表。
我们考虑把只加入的回滚莫队和只删除的回滚莫队硬缝一下,并将计算答案的过程分成两步。
第一步,首先对于一个询问
现在如果我们拿到了
所以考虑第二步,再拿一个新的链表,初始维护
另外如果
复杂度与正常的回滚莫队没有任何差异,为
代码中只定义了一个链表,并且重复利用了一下,先做了第二步,再做第一步。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>
#include <vector>
const int N = 100005, M = 300005, B = 190, C = N / B + 10;
int n, m, a[N], bel[N];
std::pair<int, int> pr[N];
int hh[N];
struct List
{
int pre[N], nxt[N];
inline void init(void)
{
nxt[0] = 1, pre[n + 1] = n;
for(int i = 1;i <= n;++i)
pre[i] = i - 1, nxt[i] = i + 1;
return;
}
inline void erase(int k)
{
nxt[pre[k]] = nxt[k], pre[nxt[k]] = pre[k];
return;
}
inline int back(int k)
{
nxt[pre[k]] = pre[nxt[k]] = k;
int res = 0x3f3f3f3f;
if(pre[k] != 0)
res = std::min(res, hh[k] - hh[pre[k]]);
if(nxt[k] != n + 1)
res = std::min(res, hh[nxt[k]] - hh[k]);
return res;
}
} L;
int ans[M];
struct node
{
int l, r, id;
inline bool operator<(node b) const
{
return r < b.r;
}
};
int big[N];
std::vector<node> vec[C];
int main(void)
{
scanf("%d", &n);
for(int i = 1;i <= n;++i)
scanf("%d", &pr[i].first), pr[i].second = i;
std::sort(pr + 1, pr + 1 + n);
for(int i = 1;i <= n;++i)
a[pr[i].second] = i, hh[i] = pr[i].first, bel[i] = (i - 1) / B + 1;
scanf("%d", &m);
for(int i = 1, l, r;i <= m;++i)
{
scanf("%d%d", &l, &r);
vec[bel[l]].push_back({l, r, i});
}
memset(ans, 0x3f, sizeof(ans));
L.init();
for(int b = 1;b <= bel[n];++b)
{
std::sort(vec[b].begin(), vec[b].end());
int bl = (b - 1) * B + 1, br = std::min(b * B, n);
for(int i = n;i >= bl;--i)
L.erase(a[i]);
int pt = bl - 1;
for(const node &x : vec[b])
{
while(pt < x.r)
L.back(a[++pt]);
int k = std::min(x.r, br);
for(int i = bl;i <= k;++i)
L.erase(a[i]);
for(int i = k;i >= x.l;--i)
ans[x.id] = std::min(ans[x.id], L.back(a[i]));
for(int i = x.l - 1;i >= bl;--i)
L.back(a[i]);
}
while(pt < n)
L.back(a[++pt]);
for(int i = bl;i <= br;++i)
L.erase(a[i]);
for(int i = n;i > br;--i)
L.erase(a[i]);
big[br] = 0x3f3f3f3f;
for(int i = br + 1;i <= n;++i)
big[i] = std::min(big[i - 1], L.back(a[i]));
for(const node &x : vec[b])
if(x.r > br)
ans[x.id] = std::min(ans[x.id], big[x.r]);
}
for(int i = 1;i <= m;++i)
printf("%d\n", ans[i]);
return 0;
}