思路:
同时支持修改,查询两种操作的莫队算法,就是带修莫队。
用两个结构体分别记录查询,修改操作;
对查询操作分区:
先将所有的查询操作分为n/unit个区块,
除了考虑l,r所在的区块,还要考虑查询的时间,均为递增排序,对所有的查询排序。
(复杂度(复杂度分析,除了要分析的那个变量是不确定的外,其他的变量全部固定不变,然后分析变量是如何变化的):
l的复杂度O(unti*m)
{只考虑l的情况,它们的l都是不同的,l至多有m种情况,每次至多变化unit*2次,所以最坏的复杂度是O(unit*m)}
r的复杂度O(n*n/unit)
{只考虑r的情况,此时l已经在同一个区间内了,r有m种情况,每次至多变化n/unit次,所以最坏的情况就是O(n*n/unit),}
tim的复杂度O((n/unit)*(n/unit))
{只考虑tim的情况,此时n与m在同一个数量级上,可以相互替换l至多前进或者后退n/unit次,r同理,
所以复杂度为O((n/unit)*(n/unit))。}
总复杂度为O(unit*n+n*n/unit+(n/unit)*(n/unit)),当unit = pow(n,2/3)时,复杂度为O(pow(n,5/3),此时的复杂度最小)
)
从区间[1,0],T = 0开始,此时ans = 0,先更新时间,然后更新左右区间的值,
然后得到这个区间内的不同颜色的笔画的数量,记录答案。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e6+10;
const double IO = 2.0/3.0;
//a数组记录每个位置糖果的不同颜色,col记录每个位置的不同颜色的数量;
//Ki数组记录每个颜色所在的区间,res数组记录最终的结果
//now数组记录每次修改后的每个位置的颜色
//ans记录某一次的区间[l,r]内的不同颜色的数量,l,r分别表示区间的两个边界,因为修改颜色时要用到,所以设置为全局变量。
int a[maxn],col[maxn]={0},Ki[maxn]={0},res[maxn] = {0},now[maxn] = {0},ans = 0,l = 1,r = 0;
struct Node{ //记录查询操作
int id,l,r,tim; //id表示第几个查询操作,l,r分别表示查询区间的左右边界,tim表示这次查询之前最近的一次修改的时间。
Node(){}
Node(int x,int y,int z,int w):id(x),l(y),r(z),tim(w){}
}qu[maxn];
struct node{
int pos,nxt,pre; //pos表示修改的颜色的位置,nxt表示改变后的颜色,pre表示改变前的颜色
node(){}
node(int x,int y,int z):pos(x),nxt(y),pre(z){}
}ca[maxn];
bool cmp(Node a,Node b){ //对查询数据进行分块排序,如果左右边界所在的区块相同,按照时间的先后顺序排列。
if(Ki[a.l]==Ki[b.l]){
if(Ki[a.r]==Ki[b.r]) return a.tim<b.tim;
return a.r<b.r;
}
return a.l<b.l;
}
void Add(int x,int d){ //修改区间[l,r]内的颜色x的数量
col[x]+=d; //颜色x的数量的该变量为d
if(d>0){ //颜色的数量增加,如果这个颜色从无到有,说明区间内的颜色种类数+1,ans+1
ans += (col[x]==1);
}
if(d<0){//颜色的数量减少,如果这个颜色的数量变为0,说明这个区间的颜色种类数-1,ans-1
ans -= (col[x]==0);
}
}
void Go(int x,int y){ //将x位置的颜色修改为颜色y
if(l<=x&&x<=r){
Add(y,1); //颜色y的数量+1
Add(a[x],-1);//颜色a[x]的数量-1
}
a[x] = y;//修改a位置的颜色
}
int main(void)
{
int n,m;
scanf("%d%d",&n,&m);
int unit = (int)pow(n,IO); //对n分区
for(int i=1;i<=n;i++) scanf("%d",&a[i]),now[i] = a[i],Ki[i] = i/unit+1;
int t1 = 0,t2 = 0;
for(int i=1;i<=m;i++){
char ss[5];int x,y;
scanf("%s%d%d",ss,&x,&y);
if(ss[0]=='Q'){//查询
qu[++t1] = Node(t1,x,y,t2);
}else{//修改
ca[++t2] = node(x,y,now[x]);now[x] = y;
}
}
sort(qu+1,qu+1+t1,cmp);
int T = 0;
for(int i=1;i<=t1;i++){
while(T<qu[i].tim){ //提前到tim时间
Go(ca[T+1].pos,ca[T+1].nxt);T++;
}
while(T>qu[i].tim){ //退后到tim时间
Go(ca[T].pos,ca[T].pre);T--;
}
while(l<qu[i].l){
Add(a[l],-1);l++;//l右移,颜色a[l]的数量-1
}
while(l>qu[i].l){
Add(a[l-1],1);l--; //l左移,颜色a[l-1]的数量+1
}
while(r<qu[i].r){
Add(a[r+1],1);r++;//r右移,颜色a[r+1]的数量+1
}
while(r>qu[i].r){
Add(a[r],-1);r--;//r左移,颜色a[r]的数量-1
}
res[qu[i].id] = ans;//记录结果。
}
for(int i=1;i<=t1;i++) printf("%d\n",res[i]);
return 0;
}