【bzoj2120】[国家集训队]数颜色[莫队]
[国家集训队]数颜色
我TM!!!!又因为数组开小了调了两个小时!!!!!!
带修莫队 只是在普通莫队上加了一个时间 然后就和普通莫队操作差不多
bzoj上直接块大小为\(\sqrt{n}\)就能过 洛谷上加了这个块的的大小只能过6个点 ==吸氧过了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define Abs(x) ((x)<0?-(x):(x))
#define ls (o<<1)
#define rs (o<<1|1)
const int N=150000+5,M=1e6+5,inf=0x3f3f3f3f;
int n,m,block,a[N],b[N],cnt[M],ans[N];
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int cq=0,cm=0;
struct quer{int l,r,tim,id;}q[N];
struct mdf{int pos,co,pre;}md[N];
bool cmp(quer A,quer B){
// return A.bl==B.bl?(A.r==B.r?A.tim<B.tim:A.r<B.r):A.bl<B.bl;
if(A.l/block!=B.l/block)return A.l/block<B.l/block;
if(A.r/block!=B.r/block)return A.r/block<B.r/block;
return A.tim<B.tim;
}
int main(){
// freopen("in.txt","r",stdin);
rd(n),rd(m),block=sqrt(n);
for(int i=1;i<=n;++i) rd(a[i]),b[i]=a[i];
for(int i=1;i<=m;++i){
char opt[2];int x,y;
scanf("%s",opt);rd(x),rd(y);
if(opt[0]=='Q') q[++cq]=(quer){x,y,cm,cq};
else md[++cm]=(mdf){x,y,b[x]},b[x]=y;
}
block=ceil(exp((log(n)+log(cq))/3));//分块大小
sort(q+1,q+cq+1,cmp);
for(int i=1;i<=n;++i) b[i]=a[i];
int l=1,r=0,tim=0,nw=0;
for(int i=1,ql,qr,qt;i<=cq;++i){
ql=q[i].l,qr=q[i].r,qt=q[i].tim;
while(l<ql) nw-=!(--cnt[a[l++]]);
while(l>ql) nw+=!cnt[a[--l]]++;
while(r<qr) nw+=!cnt[a[++r]]++;
while(r>qr) nw-=!(--cnt[a[r--]]);
while(tim<qt){
if(ql<=md[++tim].pos&&md[tim].pos<=qr) nw-=!(--cnt[a[md[tim].pos]])-!cnt[md[tim].co]++;
swap(a[md[tim].pos],md[tim].co);
}
while(tim>qt){
if(ql<=md[tim].pos&&md[tim].pos<=qr)
nw-=!(--cnt[a[md[tim].pos]])-!cnt[md[tim].co]++;
swap(a[md[tim].pos],md[tim].co),--tim;
}
ans[q[i].id]=nw;
}
for(int i=1;i<=cq;++i) printf("%d\n",ans[i]);
return 0;
}