[luoguP1903] 数颜色

题意

原题链接
给定序列 \(a\),每次查询一个区间 \([l,r]\) 中有多少个不同的数,或进行单点修改。

sol

如果不修改的话,本题就是普通莫队 [luoguSP3267] D-query
由于有修改,所以需要再增加一维,记录这次查询是在多少次修改以后查询的,然后在莫队代码后面添加对修改次数的处理,即暴力修改和还原操作。
排序时,按照先左端点块,再右端点块,最后修改次数的顺序排序,后两项可以进行奇偶性优化。每一块的大小为 \(\lfloor n^{\frac{2}{3}}\rfloor\),均摊时间复杂度为 \(O(n^{\frac{5}{3}})\)

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define x first 
#define y second 

using namespace std;
typedef pair<int, int> PII;

const int N = 150005, M = 1000005;

int n, m;
int c[N];
int buc[M], ans[N], block[N], res = 0;
PII modify[N];

struct Ask{
    int l, r, t, id;

    bool operator< (const Ask &W) const {
        if (block[l] != block[W.l]) return block[l] < block[W.l];
        if (block[r] != block[W.r]) return block[r] < block[W.r];
        return t < W.t;
    }
} queries[N];

void add(int x){
    if (!buc[x]) res ++ ;
    buc[x] ++ ;
}

void del(int x){
    buc[x] -- ;
    if (!buc[x]) res -- ;
}

int main(){
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]);

    int qcnt = 0, mcnt = 0;
    for (int i = 1; i <= m; i ++ ){
        char op[2];
        int x, y;
        scanf("%s%d%d", op, &x, &y);
        if (*op == 'Q') qcnt ++ , queries[qcnt] = {x, y, mcnt, qcnt};
        else modify[ ++ mcnt] = {x, y};
    }

    int Sz = pow(n, 0.667);
    int bcnt = ceil(1.0 * n / Sz);

    for (int i = 1; i <= bcnt; i ++ )
        for (int j = (i - 1) * Sz + 1; j <= min(n, i * Sz); j ++ )
            block[j] = i;

    sort(queries + 1, queries + qcnt + 1);

    int l = 1, r = 0, time = 0;
    for (int i = 1; i <= qcnt; i ++ ){
        int ql = queries[i].l, qr = queries[i].r, qt = queries[i].t;
        while (l > ql) add(c[ -- l]);
        while (r < qr) add(c[ ++ r]);
        while (l < ql) del(c[l ++ ]);
        while (r > qr) del(c[r -- ]);
        while (time < qt) {
            time ++ ;
            if (ql <= modify[time].x && modify[time].x <= qr) {
                add(modify[time].y);
                del(c[modify[time].x]);
            }
            swap(modify[time].y, c[modify[time].x]);
        }
        while (time > qt) {
            if (ql <= modify[time].x && modify[time].x <= qr) {
                add(modify[time].y);
                del(c[modify[time].x]);
            }
            swap(modify[time].y, c[modify[time].x]);
            time -- ;
        }

        ans[queries[i].id] = res;
    }

    for (int i = 1; i <= qcnt; i ++ ) printf("%d\n", ans[i]);

    return 0;
}

蒟蒻犯的若至错误

  • 忘排序了 awa
posted @ 2024-11-25 21:21  是一只小蒟蒻呀  阅读(8)  评论(0编辑  收藏  举报