SP30906 ADAUNIQ - Ada and Unique Vegetable 题解
带修莫队板子题。
在静态莫队的基础上,加一个指针扫描时间轴即可。
令 $c_i$ 表示时间为 $t$ 时 $[l,r]$ 内 $i$ 的出现次数。
指针移动时,令 $c_x\gets c_x+k$ 前,答案 $q\gets q-[c_x=1]+[c_x+k=1]$。
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, b, q, c1, c2, a[200050], t[200050], c[200050], s[200050];
struct S
{
int x, y, z, i;
} q1[200050], q2[200050];
void I(int x)
{
q -= c[x] == 1;
q += !c[x]++;
}
void D(int x)
{
q -= !--c[x];
q += c[x] == 1;
}
bool C(S a, S b) { return t[a.x] == t[b.x] ? t[a.y] == t[b.y] ? a.z < b.z : a.y < b.y : a.x < b.x; }
void M(int x, int i)
{
if (q1[i].x <= q2[x].x && q2[x].x <= q1[i].y)
D(a[q2[x].x]), I(q2[x].y);
swap(a[q2[x].x], q2[x].y);
}
int main()
{
scanf("%d%d", &n, &m);
b = pow(n, 2.0 / 3);
for (int i = 1; i <= n; ++i)
scanf("%d", a + i), ++a[i], t[i] = (i - 1) / b + 1;
for (int i = 0, o, x, y; i < m; ++i)
{
scanf("%d%d%d", &o, &x, &y);
++x;
++y;
if (o == 2)
++c1, q1[c1] = {x, y, c2, c1};
else
q2[++c2] = {x, y};
}
sort(q1 + 1, q1 + c1 + 1, C);
for (int i = 1, x = 1, y = 0, z = 0; i <= c1; ++i)
{
while (x > q1[i].x)
I(a[--x]);
while (y < q1[i].y)
I(a[++y]);
while (x < q1[i].x)
D(a[x++]);
while (y > q1[i].y)
D(a[y--]);
while (z < q1[i].z)
M(++z, i);
while (z > q1[i].z)
M(z--, i);
s[q1[i].i] = q;
}
for (int i = 1; i <= c1; ++i)
printf("%d\n", s[i]);
return 0;
}