- 题意:
给一个序列,每个位置对应一个值,支持下面两种操作:
1.修改某个位置的值。
2.询问(l,r)区间内不同值的个数。
- 题解:
1.考虑分块:统计ans[i][j]表示第i块到第j块的个数,容易发现对于每个询问,只需查看完整块的个数和不完整块的影响。时间复杂度 O(n⋅n√) 。但修改会修改两两块之间的ans[i][j],时间复杂度 O(n⋅m) (这道题修改只有1000个,可以过去)。
2.莫队算法:如果没有修改操作莫队直接秒,有修改操作写莫队就有点麻烦,要加一个时间的维度。具体不再赘述,可以尝试一下,也可以过。
3.还是考虑分块:对于每一个位置记录前面相同颜色最近出现的位置pre[i]。对于一个查询就是查询块中pre[i]小于l的个数。分块并排序,块内二分查找。时间复杂度 O(n⋅n√⋅logn√) 。修改操作暴力修改,如果不同就重建。(反正只改一个位置,最多也只重建前后影响的几个块)。时间复杂度 m⋅(n+n√⋅logn√) 。
第一种和第三种本质上是差不多的,但第一种难写一点,这里给出第三种的代码:
- Code
#include<bits/stdc++.h>
using namespace std;
const int Maxn=3e4+50;
const int Maxm=3e4+50;
int S=140;
inline int read()
{
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
int n,m,a[Maxn],bg[Maxn],ed[Maxn],s1,pre[Maxn],last[Maxn],s,b[Maxn];
char Ch[2];
struct node
{
int val,id,op;
friend inline bool operator <(const node &a,const node &b){return a.val<b.val;}
}B[Maxn+Maxm];
struct Node
{
int pos,val,op;
}q[Maxn];
inline void l_b()
{
sort(B+1,B+s1+1);
int t=0;
for(int i=1;i<=s1;i++)
{
if(i==1||B[i].val!=B[i-1].val)t++;
if(B[i].op)a[B[i].id]=t;
else q[B[i].id].val=t;
}
}
inline void Pre()
{
for(int i=1;i<=n;i++)
{
pre[i]=last[a[i]];
last[a[i]]=i;
}
for(int i=1;i*S<=n;i++)s=i,bg[i]=ed[i-1]+1,ed[i]=ed[i-1]+S;
if(ed[s]!=n)s++,bg[s]=ed[s-1]+1,ed[s]=n;
for(int i=1;i<=n;i++)b[i]=pre[i];
for(int i=1;i<=s;i++)sort(b+bg[i],b+ed[i]+1);
}
int buf[50];
inline void W(int x)
{
if(!x)putchar('0');
if(x<0)putchar('-'),x=-x;
while(x)buf[++buf[0]]=(x%10),x/=10;
while(buf[0])putchar('0'+buf[buf[0]--]);
}
inline int calc(int now,int val)
{
int l=bg[now],r=ed[now],L;
while(l<=r)
{
int mid=(l+r)>>1;
if(b[mid]<val)l=mid+1,L=mid;
else r=mid-1;
}
if(r==bg[now]-1)L=bg[now]-1;
return L-bg[now]+1;
}
inline void rebuild(int x)
{
for(int i=bg[x];i<=ed[x];i++)b[i]=pre[i];
sort(b+bg[x],b+ed[x]+1);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)B[++s1].val=read(),B[s1].id=i,B[s1].op=1;
for(int i=1;i<=m;i++)
{
scanf("%s",Ch+1);
if(Ch[1]=='Q')q[i].op=0;
else q[i].op=1;
q[i].pos=read();
q[i].val=read();
if(Ch[1]=='R')
{
B[++s1].val=q[i].val;
B[s1].op=0;
B[s1].id=i;
}
}
l_b();
Pre();
for(int i=1;i<=m;i++)
{
if(q[i].op)
{
for(int j=1;j<=n;j++){last[a[j]]=0;}
a[q[i].pos]=q[i].val;
for(int j=1;j<=n;j++)
{
int t=pre[j];
pre[j]=last[a[j]];
if(pre[j]!=t)rebuild((j-1)/S+1);
last[a[j]]=j;
}
}
else
{
int l=q[i].pos,r=q[i].val;
int ans=0;
if (r-l+1>2*S)
{
int L=(l-1)/S+1,R=(r-1)/S+1;
if(bg[L]!=l)L++;
if(ed[R]!=r)R--;
for(int i=L;i<=R;i++)ans+=calc(i,l);
for(int i=l;i<bg[L];i++)if(pre[i]<l)ans++;
for(int i=ed[R]+1;i<=r;i++)if(pre[i]<l)ans++;
W(ans);putchar('\n');
}
else
{
for(int i=l;i<=r;i++)if(pre[i]<l)ans++;
W(ans);putchar('\n');
}
}
}
}