[luoguP1903] 数颜色

题意

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

sol

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

代码

#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 @   是一只小蒟蒻呀  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示