题目
题目传送门
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0e77e2e70bc4165345ed7c2b96190696.png)
![](https://i-blog.csdnimg.cn/blog_migrate/89945e4ebf6427be96da2fef6c2d5cb9.png)
题解
根据题意,我们有一些修改操作,所以这是一个带修莫队(废话)- 那么再给出的每个操作中,修改和询问是有顺序的,所以我们在排序是需要在加上一个时间的排序,来达到优化。
- 当我们在查询时可再填加一个时间指针来表示到目前为止已经进行了几次修改,如果修改的次数大于当前要修改的问题编号,则把它还原,否则更新即可。
- 块的大小为
n
2
3
n^{\frac{2}{3}}
n32
(不会证明,记住即可)
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 100;
const int maxm = 1e6 + 100;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, m, csize, qsize, ans;
int a[maxn], res[maxn], pos[maxn], cnt[maxm];
struct change { int p, col; } c[maxn];
struct query { int l, r, t, id; } q[maxn];
inline bool cmp(query aa, query bb) {
return pos[aa.l] == pos[bb.l] ? (pos[aa.r] == pos[bb.r] ? aa.t < bb.t : aa.r < bb.r) : aa.l < bb.l;
}
inline void del(int x) { if (--cnt[x] == 0) --ans; }
inline void add(int x) { if (++cnt[x] == 1) ++ans; }
int main() {
read(n), read(m);
int blo = pow(n, 0.666666);
for (int i = 1; i <= n; ++i) {
read(a[i]);
pos[i] = i / blo;
}
char opt[10];
for (int i = 1; i <= m; ++i) {
scanf("%s", opt);
if (opt[0] == 'Q') {
++qsize;
read(q[qsize].l), read(q[qsize].r);
q[qsize].t = csize;
q[qsize].id = qsize;
}
else {
++csize;
read(c[csize].p), read(c[csize].col);
}
}
sort(q + 1, q + qsize + 1, cmp);
int l = 1, r = 0, t = 0;
for (int i = 1; i <= qsize; ++i) {
int ql = q[i].l, qr = q[i].r;
while (t < q[i].t) {
++t;
if (l <= c[t].p && r >= c[t].p) {
del(a[c[t].p]);
add(c[t].col);
}
swap(a[c[t].p], c[t].col);
}
while (t > q[i].t) {
if (l <= c[t].p && r >= c[t].p) {
del(a[c[t].p]);
add(c[t].col);
}
swap(a[c[t].p], c[t].col);
--t;
}
while (l < ql) del(a[l++]);
while (l > ql) add(a[--l]);
while (r < qr) add(a[++r]);
while (r > qr) del(a[r--]);
res[q[i].id] = ans;
}
for (int i = 1; i <= qsize; ++i)
printf("%d\n", res[i]);
return 0;
}