【模板】回滚莫队&不删除莫队
题目链接:luogu P5906
题目大意
给你一个序列,多次询问每次问一个区间,求里面相同的数的最远间隔距离。
思路
考虑莫队,发现加入一个点好处理,但是删去不好处理。
考虑莫队能不能不删去,那我们考虑把删去变成从头再加。
啊当然不行,那能不能选一个节点,每次改左边就从这个节点从新向左边扩展。
距离来说就是对于一个块 \(x\),我们枚举作为左端点所在块,那我们按右端点排序,每次确定好右端点,我们就把左端点从这个块的右端开始往左移,从而来加进去。
然后在这题里面你要维护的就是最左的某个数和最右的某个数(用桶来维护)。
然后记得还原操作不要用 memset 而是按之前贡献的路取消回去。
(也可以拿一个桶记录修改了什么地方)
具体操作看代码。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 100;
int n, a[N], B, m, blo[N], bl[N], br[N];
int lst[N], ans[N], Rlst[N], Llst[N];
int clr[N], b[N], bn;
struct Quest {
int l, r, id;
}q[N];
bool cmp(Quest x, Quest y) {
if (blo[x.l] != blo[y.l]) return blo[x.l] < blo[y.l];
return x.r < y.r;
}
int clac(int l, int r) {
int re = 0;
for (int i = l; i <= r; i++)
if (!lst[a[i]]) lst[a[i]] = i;
else re = max(re, i - lst[a[i]]);
for (int i = l; i <= r; i++) lst[a[i]] = 0;
return re;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
//离散
memcpy(b, a, sizeof(b)); sort(b + 1, b + n + 1); bn = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + bn + 1, a[i]) - b;
B = sqrt(n);
for (int i = 1; i <= n; i++) {
blo[i] = (i - 1) / B + 1;
if (!bl[blo[i]]) bl[blo[i]] = i;
br[blo[i]] = i;
}
scanf("%d", &m);
for (int i = 1; i <= m; i++) scanf("%d %d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q + m + 1, cmp);
int now = 1;
for (int i = 1; i <= blo[n]; i++) {
int mid = br[i], l = mid + 1, r = mid, val = 0;
while (now <= m && blo[q[now].l] == i) {
if (blo[q[now].r] == i) {
ans[q[now].id] = clac(q[now].l, q[now].r);
now++; continue;
}
while (r < q[now].r) {
r++;
Rlst[a[r]] = r;
if (!Llst[a[r]]) Llst[a[r]] = r, clr[++clr[0]] = a[r];
else val = max(val, r - Llst[a[r]]);
}
int tmp = val;
while (l > q[now].l) {
l--;
if (!Rlst[a[l]]) Rlst[a[l]] = l;
else val = max(val, Rlst[a[l]] - l);
}
while (l < mid + 1) {
if (Rlst[a[l]] == l) Rlst[a[l]] = 0;
l++;
}
ans[q[now].id] = val; val = tmp;
now++;
}
for (int j = 1; j <= clr[0]; j++) Llst[clr[j]] = Rlst[clr[j]] = 0; clr[0] = 0;
}
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}
标签:回滚,P5906,val,Rlst,int,blo,include,莫队
From: https://www.cnblogs.com/Sakura-TJH/p/luogu_P5906.html