题意:
思路:
第一次写带修莫队,感觉还是比较简单的,相对于普通莫队,带修莫队主要是加了一个时间标志。大致思路就是,因为区间内的东西要修改,那就干脆继续暴力的修改,把[L,R]的转移,看成[L,R,T]的转移,依旧是利用排序进行优化,可以说带修莫队依旧是个暴力的优化。
不过,这题有一个疑点,就是在查看许多的博客里面,对于带修莫队,都说block为
n23
n
2
3
时带修莫队速度达到最优,为O(
n53
n
5
3
)。理论值的确是这样,可是在这道题目里面,实际写起来把block写成
n‾√
n
比
n23
n
2
3
快300ms以上
错误及反思:
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int pos[N],arr[N],ans[N],last[N];
int times[N];
int n,m,qt,ct,now;
struct Query
{
int l,r,id,tim;
}q[N];
struct C
{
int pre,pos,to;
}c[N];
bool cmp(Query a,Query b){
if(pos[a.l]!=pos[b.l])
return a.l<b.l;
else if(pos[a.r]!=pos[b.r])
return a.r<b.r;
return a.tim<b.tim;
}
void change(int x,int y){
int temp=times[x];
times[x]+=y;
if(temp==1&×[x]==0)
now--;
else if(temp==0&×[x]==1)
now++;
}
int main(){
scanf("%d%d",&n,&m);
int block=pow(n,0.66666);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
last[i]=arr[i];
pos[i]=i/block;
}
qt=0,ct=0,now=0;
for(int i=0;i<m;i++)
{
char temp[5];
scanf("%s",temp);
if(temp[0]=='Q'){
scanf("%d%d",&q[qt].l,&q[qt].r);
q[qt].id=qt;
q[qt++].tim=ct;
}
else
{
scanf("%d%d",&c[ct].pos,&c[ct].to);
c[ct].pre=last[c[ct].pos];
last[c[ct].pos]=c[ct++].to;
}
}
sort(q,q+qt,cmp);
for(int i=0,l=1,r=0,t=0;i<qt;i++)
{
for(;t<q[i].tim;t++)
{
int t1=times[c[t].pre];
int t2=times[c[t].to];
if(c[t].pos>=l&&c[t].pos<=r)
{
times[c[t].pre]--;times[c[t].to]++;
}
if(t1==1&×[c[t].pre]==0)
now--;
else if(t1==0&×[c[t].pre]==1)
now++;
if(t2==1&×[c[t].to]==0)
now--;
else if(t2==0&×[c[t].to]==1)
now++;
arr[c[t].pos]=c[t].to;
}
for(;t>q[i].tim;t--)
{
int t1=times[c[t-1].pre];
int t2=times[c[t-1].to];
if(c[t-1].pos>=l&&c[t-1].pos<=r)
{
times[c[t-1].to]--;times[c[t-1].pre]++;
}
if(t1==1&×[c[t-1].pre]==0)
now--;
else if(t1==0&×[c[t-1].pre]==1)
now++;
if(t2==1&×[c[t-1].to]==0)
now--;
else if(t2==0&×[c[t-1].to]==1)
now++;
arr[c[t-1].pos]=c[t-1].pre;
}
for(;l<q[i].l;l++)
change(arr[l],-1);
for(;l>q[i].l;l--)
change(arr[l-1],1);
for(;r<q[i].r;r++)
change(arr[r+1],1);
for(;r>q[i].r;r--)
change(arr[r],-1);
ans[q[i].id]=now;
}
for(int i=0;i<qt;i++)
printf("%d\n",ans[i]);
}