SP30906 解题报告

题目传送门

题目大意:

给定一个长度为 \(n\) 的序列,\(q\) 次询问区间 \([l, r]\) 内只出现过一次的数有多少个。

思路:

很明显带修莫队可以做。

复习一下,带修莫队就是在普通莫队的基础上加上了时间轴,把操作分为询问操作和修改操作两种分别存下来。

因为修改是有顺序的,每次修改只会会对它之后的查询操作有变动,而对它之前的查询不影响。

令当前时间为 \(t\),若当前时间小于所处理的查询操作的时间,就将时间往后推进,增添几个修改,反之时间回溯,减少几个修改,直到当前的所有变量与所查询区间重合。

通俗地讲,就是再弄一指针,在修改操作上跳来跳去,如果当前修改多了就改回来,改少了就改过去,直到次数恰当为止。

排序也需要加上时间这一关键字。

就题而言,因为只要求出现一次的数字个数,所以在加数时若没出现过则答案 \(+1\),否则若刚好出现过一次就要 \(-1\)。删数操作大同小异。

\(\texttt{Code:}\)

#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 200010;

int n, m;
int a[N];
int len;
inline int get(int x) {return x / len;}

struct Q{
    int id, l, r, t;
    bool operator <(const Q &o) const{
        if(get(l) != get(o.l)) return l < o.l;
        if(get(r) != get(o.r)) return r < o.r;
        return t < o.t; 
    }
}q[N];
int ttq;
struct M{
    int x, y;
}qc[N];
int ttc;
int cnt[N];
int ans[N];

inline void add(int x, int &res) {
    if(!cnt[x]) res++;
    else if(cnt[x] == 1) res--;
    cnt[x]++;
}

inline void del(int x, int &res) {
    cnt[x]--;
    if(!cnt[x]) res--;
    else if(cnt[x] == 1) res++;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    int op, x, y;
    while(m--) {
        scanf("%d%d%d", &op, &x, &y);
        if(op == 2) q[++ttq] = {ttq, x + 1, y + 1, ttc};
        else qc[++ttc] = {x + 1, y};
    }
    len = pow(n, 2.0 / 3); //从队内大佬处学来的玄学块长
    sort(q + 1, q + ttq + 1);
    int id, l, r, tg;
    for(int i = 0, j = 1, t = 0, k = 1, res = 0; k <= ttq; k++) {
        id = q[k].id, l = q[k].l, r = q[k].r, tg = q[k].t;
        while(i < r) add(a[++i], res);
        while(i > r) del(a[i--], res);
        while(j < l) del(a[j++], res);
        while(j > l) add(a[--j], res);
        while(t < tg) {
            ++t;
            if(qc[t].x >= j && qc[t].x <= i) {
                del(a[qc[t].x], res);
                add(qc[t].y, res);
            }
            swap(a[qc[t].x], qc[t].y);
        }
        while(t > tg) {
            if(qc[t].x >= j && qc[t].x <= i) {
                del(a[qc[t].x], res);
                add(qc[t].y, res);
            }
            swap(a[qc[t].x], qc[t].y);
            --t;
        }
        ans[id] = res;
    }
    for(int i = 1; i <= ttq; i++)
        printf("%d\n", ans[i]);
    return 0;
}
posted @ 2024-09-04 20:34  Brilliant11001  阅读(4)  评论(0编辑  收藏  举报