题目
思路
这里如果没有修改,就是个普通莫队。
但修改就很优(恶)美(心)。
我们可以加上一位时间轴。
由数据范围得,块长应设为
n
2
3
n^{2\over 3}
n32……
然后就是时间轴,左端点,右端点的移动,与普通莫队没多大差别,不会的可以看代码。
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
//When I wrote this code,God and I unterstood what was I doing
int n,m,color[1000001],t,cnt[1000001],block[1000001],tot,len,nt[1000001];//数组尽量大,反正不要钱
bool vis[1000001];
inline int read()
{
int ret,c,f=1;
while (((c=getchar())> '9'||c< '0')&&c!='-');
if (c=='-') f=-1,ret=0;
else ret=c-'0';
while ((c=getchar())>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+(c^48);
return ret*f;
}
struct quant{
int id,l,r,t;
} q[1000001];
struct ask{
int x,p,nxt;
} c[1000001];
int ans[1000001],siz;
bool cmp(quant a,quant b)
{
if (block[a.l]==block[b.l])
{
if (block[a.r]==block[b.r])
{
return a.t<b.t;
}
return block[a.r]<block[b.r];
}
return block[a.l]<block[b.l];
}
void myd(int x)
{
if (vis[x])
{
cnt[color[x]]--;
if (!cnt[color[x]]) siz--;
}
else
{
cnt[color[x]]++;
if (cnt[color[x]]==1) siz++;
}
vis[x]^=1;
return;
}
void change(int x,int y)
{
if (vis[x])
{
myd(x);
color[x]=y;
myd(x);
}
else color[x]=y;
return;
}
int main()
{
n=read(),m=read();
len=pow(n,2.0/3.0);
for (int i=1;i<=n;i++) color[i]=nt[i]=read(),block[i]=(i-1)/len+1;
for (int i=1;i<=m;i++)
{
char opt;
cin>>opt;
if (opt=='Q')
{
q[++tot].l=read(),q[tot].r=read(),q[tot].t=t,q[tot].id=tot;
}
else
{
c[++t].x=read(),c[t].p=read(),c[t].nxt=nt[c[t].x],nt[c[t].x]=c[t].p;
}
}
sort(q+1,q+1+tot,cmp);
t=0;
int l=1,r=0;
for (int i=1;i<=tot;i++)
{
while (t<q[i].t) t++,change(c[t].x,c[t].p);
while (t>q[i].t) change(c[t].x,c[t].nxt),t--;
while (l<q[i].l) myd(l),l++;
while (l>q[i].l) l--,myd(l);
while (r<q[i].r) r++,myd(r);
while (r>q[i].r) myd(r),r--;
ans[q[i].id]=siz;
}
for (int i=1;i<=tot;i++) cout<<ans[i]<<endl;
return 0;
}
//Now,only God know