[国家集训队]数颜色 / 维护队列 (带修改莫队)
题目链接
题解
树套树做法暂时不会,先坑着
带修改的莫队
在普通莫队基础上加一个时间量
修改时调整区间,同时调整时间
具体看代码
Code
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
const int N = 2000010, M = 50010;
int n, m, C[N], belong[N];
struct qus {
int l, r, id, tim;//tim记录在这次询问之前最近它的修改
bool operator <(qus z) const {
if (belong[l] == belong[z.l]) {
if (belong[r] == belong[z.r])
return tim < z.tim;
return r < z.r;
}
return l < z.l;
}
}q[M];
struct node {
int pos, v;
}o[M];
//o记录修改操作,q记录询问
int cnt1, cnt2;
int tot[N], ans, a[M];
inline void del(int c) {if(!(--tot[c])) ans--;}//删掉
inline void add(int c) {if(++tot[c] == 1) ans++;}//添加
inline void change(int now, int k) {
if (q[k].l <= o[now].pos && o[now].pos <= q[k].r)
del(C[o[now].pos]), add(o[now].v);
swap(C[o[now].pos], o[now].v);//这里是交换,因为后面撤销操作需要掉换回来
return ;
}
inline int gi() {
RG int x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
return f ? -x : x;
}
int main() {
int n = gi(), m = gi(), siz = pow(n, 0.666666666666);//siz为块的大小
for (RG int i = 1; i <= n; i++) C[i] = gi(), belong[i] = (i-1)/siz+1;
char type;
while (m--) {
scanf("\n%c", &type);
if (type == 'Q') {
q[++cnt1].l = gi(); q[cnt1].r = gi(); q[cnt1].id = cnt1; q[cnt1].tim = cnt2;
}
else o[++cnt2].pos = gi(), o[cnt2].v = gi();
}
sort(q+1, q+1+cnt1);
int l = 1, r = 0, now = 0;
for (int i = 1; i <= cnt1; i++) {
while (l > q[i].l) add(C[--l]);
while (l < q[i].l) del(C[l++]);
while (r < q[i].r) add(C[++r]);
while (r > q[i].r) del(C[r--]);
while (now < q[i].tim) change(++now, i);
while (now > q[i].tim) change(now--, i);
a[q[i].id] = ans;
}
for (int i = 1; i <= cnt1; i++)
printf("%d\n", a[i]);
return 0;
}