这是一篇很简略的题解,只是用来提醒自己待修莫队怎么写,部分摘录了其他人的博客,代码也是好久之前写的 。
题意
墨墨购买了一套 N N N 支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
-
Q L R Q\ L\ R Q L R 代表询问你从第 L L L 支画笔到第 R R R 支画笔中共有几种不同颜色的画笔。
-
R P C R\ P\ C R P C 把第 P P P 支画笔替换为颜色 C C C。
对于每一个 Q Q Q 的询问,你需要在对应的行中给出一个数字,代表第 L L L 支画笔到第 R R R 支画笔中共有几种不同颜色的画笔。
n , m ≤ 133333 n,m \leq 133333 n,m≤133333。
思路
这个区间的 count,肯定想用莫队维护区间的桶,询问就是这样。但是还有个修改操作。因此需要使用带修莫队。
带修莫队的原理,转载自子相詹的这篇博客。
对询问加入时间戳 t t t(即该操作在第 t t t 个修改操作之后),并添加一个时间指针,在移动指针时优先移动时间指针。
排序方式转变为:以左端点所在块为第一关键字,右端点所在块为第二关键字,时间戳为第三关键字进行排序 块长定义为 n 2 3 n^{\frac{2}{3}} n32,因此总复杂度复杂度为 Θ ( n 5 3 ) \Theta(n^{\frac{5}{3}}) Θ(n35) 级别。
普通莫队由于没有修改,因而时间戳均为 0 0 0,所以可以将普通莫队看作带修莫队的一个特殊情况。这也就是说,只有两个询问处于同一个时间点,就能放心大胆地移动指向询问的指针。在移动完双指针后,上一个询问与当前询问便会处于同一个时间点内,即两个询问之间没有修改,于是问题被转化成了普通莫队。
我们按图索骥,给询问搞上时间戳然后进行排序。另开一个指针搞修改。
同时注意审题,是第 p p p 支换乘颜色为 x x x 的。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline void write(ll x)
{
if(x==0){putchar('0');return;}
ll len=0,k1=x,c[10005];
if(k1<0)k1=-k1,putchar('-');
while(k1)c[len++]=k1%10+'0',k1/=10;
while(len--)putchar(c[len]);
}
const ll N=1e6+9;
ll n,m,a[N],l,r;
ll bitSize,res,b[N],cnt[N],ans[N];
ll nq;
//char op;
struct query
{
ll l,r,t,id;
}q[N];
bool cmp(const query &x,const query &y)
{
return b[x.l]==b[y.l]?(b[x.r]==b[y.r]?x.t<y.t:b[x.r]<b[y.r]):b[x.l]<b[y.l];
}
ll ti;
struct modify
{
ll p,x;
}modi[N];
void add(ll x)
{
cnt[x]++;
if(cnt[x]==1)res++;
}
void del(ll x)
{
cnt[x]--;
if(cnt[x]==0)res--;
}
void M(ll t,ll i)
{
if(q[i].l<=modi[t].p&&modi[t].p<=q[i].r)//第p支->x
{
add(modi[t].x);
del(a[modi[t].p]);
}
swap(modi[t].x,a[modi[t].p]);
}
int main()
{
n=read(),m=read();
bitSize=pow(n,0.667);//n^(2/3)
for(int i=1;i<=n;i++)
{
a[i]=read();
b[i]=(i-1)/bitSize+1;
}
for(int i=1;i<=m;i++)
{
// cin>>op;
char op[3];
scanf("%s",&op);
l=read(),r=read();
if(op[0]=='Q')q[++nq]=(query){l,r,ti,nq};
else modi[++ti]=(modify){l,r};
}
sort(q+1,q+nq+1,cmp);
ll l=1,r=0,t=0;
for(int i=1;i<=nq;i++)
{
while(l<q[i].l)del(l++);
while(r>q[i].r)del(r--);
while(l>q[i].l)add(--l);
while(r<q[i].r)add(++r);
while(t<q[i].t)M(++t,i);
while(t>q[i].t)M(t--,i);
ans[q[i].id]=res;
}
for(int i=1;i<=nq;i++)
write(ans[i]),puts("");
return 0;
}