题目大意:给你[0,n-1]的序列,有m个操作,Q l r询问[L,R-1]区间内的不同的数字的个数,M x y为修改a[x]=y。
思路:利用可修改的莫队,将(L,R,x)作为三元组进行分块。L的块作为第一关键字,R的块作为第二关键字,第x次修改作为第三关键字。每一次扩展区间后模拟修改过程。
俗话说得好 莫队就是分块之后暴力乱搞233
#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<cstdio>
#include<stdio.h>
#include<set>
#include<map>
#include<deque>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<list>
#include<fstream>
#include<bitset>
#include <ctime>
using namespace std;
//加速cin
/*ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);*/
typedef long long ll;
const int maxn = 50010;
char * cp = (char *)malloc(20000000);
inline void in(int &x) {
while (*cp<'0' || *cp>'9')++cp;
for (x = 0;*cp >= '0'&&*cp <= '9';)x = x * 10 + (*cp++^'0');
}
inline void in(char &x) {
while (*cp == '\n' || *cp == ' ')++cp;
x = (*cp);
}
int Lid[maxn], Rid[maxn], a[maxn];
int pre[maxn], ct[maxn * 21];//ct存取a[x]在区间内出现的次数
int cg[maxn][3];//记录修改
int now;
int ans[maxn];
struct ask
{
int l, r, c, id;
friend bool operator < (const ask& x, const ask& y)
{
if (Lid[x.l] == Lid[y.l])
{
if (Rid[x.r] == Rid[y.r])
return x.c < y.c;
else return Rid[x.r] < Rid[y.r];
}
return Lid[x.l] < Lid[y.l];
}
}q[maxn];
void up(int l, int r, int& im, int t)
{
while (im != t)
{
im++;
a[cg[im][2]] = cg[im][1];
if (cg[im][2] < l || cg[im][2] > r) { continue; }
ct[cg[im][1]]++;ct[cg[im][0]]--;
if (ct[cg[im][1]] == 1 && cg[im][1]!=cg[im][0])now++;
if (ct[cg[im][0]] == 0 && cg[im][1] != cg[im][0])now--;
}
}
void down(int l, int r, int& im, int t)
{
while (im != t)
{
a[cg[im][2]] = cg[im][0];
if (cg[im][2] < l || cg[im][2] > r) { im -= 1; continue; }
ct[cg[im][0]]++;ct[cg[im][1]]--;
if (ct[cg[im][0]] == 1 && cg[im][1] != cg[im][0])now++;
if (ct[cg[im][1]] == 0 && cg[im][1] != cg[im][0])now--;
im--;
}
}
void add(int x, int d)
{
ct[a[x]] += d;
if (ct[a[x]] == 0 && d < 0)now--;
else if (ct[a[x]] == 1 && d > 0)now++;
}
int main()
{
int n, m, sz;
fread(cp, 1, 20000000, stdin);
in(n), in(m);
sz = sqrt(n);
for (int i = 0;i < n;i++)
{
in(a[i]);
Rid[i] = Lid[i] = i / sz + 1;//初始化分块
pre[i] = a[i];
}
char cmd;int l, r, cnt = 1,id = 0;
for (int i = 0;i < m;i++)
{
in(cmd);in(l), in(r);
if (cmd == 'Q')
{
q[id].id = id;
q[id].l = l;
q[id].r = r - 1;
q[id++].c = cnt - 1;
}
else
{
cg[cnt][2] = l; //第三位存修改的位置
cg[cnt][0] = pre[l]; //第一位存原来的数
cg[cnt++][1] = r; //第二位存新的数
pre[l] = r;
}
}
sort(q, q + id);
l = 0, r = 0, cnt = 0, ct[a[0]] = 1, now = 1;
for (int i = 0;i < id;i++)
{
while (l < q[i].l) { add(l, -1);l++; }
while (r > q[i].r) { add(r, -1);r--; }
while (l > q[i].l) { add(l - 1, 1);l--; }
while (r < q[i].r) { add(r + 1, 1);r++; }
if (cnt > q[i].c)//模拟从第cnt次更新到第q[i].c的更新
down(l, r, cnt, q[i].c);
else if (cnt < q[i].c)
up(l, r, cnt, q[i].c);
ans[q[i].id] = now;
}
for (int i = 0;i < id;i++)printf("%d\n", ans[i]);
return 0;
}