CF351D Jeff and Removing Periods
HH的项链 加强版本。
容易发现,这肯定和一段区间内数的种类数有关,然后,因为第一次操作的时候不能重排数列,那么我们只用讨论第一次的情况:
- 可以一次把这种数删完。
- 不能一次把这种数删完。
那么我们可以记录一个 (fa_{i}) 代表 (i) 前面只要跨过区间 ([fa_i, i]) 就不能一次把这种数删完的第一个点。
可以发现有两种转移
[fa_{i} = pre_{pre_{i}} [i - pre_{i}
e pre_{i} - pre_{pre_{i}}]
]
[fa_{i} = fa_{pre_{i}} [i - pre_{i} = pre_{i} - pre_{pre_{i}}]
]
然后整俩树状数组一整就完了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+10;
ll N, M, val[MAXN], nxt[MAXN], lst[MAXN], pre[MAXN], fa[MAXN], ans[MAXN];
struct que {
ll l, r, id;
friend bool operator < (que a, que b) {return a.r < b.r;}
} Q[MAXN];
struct arr {
ll C[MAXN];
void add(ll x, ll v) {
if (!x) return;
while (x <= N) {
C[x] += v;
x += (x & (-x));
}
}
ll ask(ll x) {
ll ret = 0;
while (x) {
ret += C[x];
x -= (x & (-x));
}
return ret;
}
} t1, t2;
int main() {
scanf("%lld", &N);
for (ll i = 1; i <= N; i++) {
scanf("%lld", val+i);
nxt[lst[val[i]]] = i;
pre[i] = lst[val[i]];
lst[val[i]] = i;
if (i - pre[i] == pre[i] - pre[pre[i]]) fa[i] = fa[pre[i]];
else fa[i] = pre[pre[i]];
}
scanf("%lld", &M);
for (ll i = 1; i <= M; i++)
scanf("%lld%lld", &Q[i].l, &Q[i].r), Q[i].id = i;
sort(Q+1, Q+M+1);
ll now = 0;
for (ll i = 1; i <= M; i++) {
while (now < Q[i].r) {
++now;
t1.add(now, 1);
t1.add(pre[now], -1);
t2.add(fa[now], 1);
t2.add(fa[pre[now]], -1);
}
ll tem1 = t1.ask(Q[i].r) - t1.ask(Q[i].l - 1), tem2 = t2.ask(Q[i].r) - t2.ask(Q[i].l - 1);
ans[Q[i].id] = tem1 + (tem1 == tem2);
}
for (ll i = 1; i <= M; i++)
printf("%lld
", ans[i]);
return 0;
}