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;
}
posted @ 2023-04-19 18:26  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源