P1903 [国家集训队]数颜色 带修改莫队板子

大概就是要多加一维time

然后按照(l的块,r的块,time)为关键字排序

转移区间修改还是按照莫队的方式(每个修改要记修改前后的状态)

然后玄学dalao告诉窝块大小设为\(O(n^{\frac{2}{3}})\)最优

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
	rg int x=0,f=1;rg char ch=getchar();
	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int maxn=10010;
int A[maxn];
int p[maxn],pa[maxn],pb[maxn];
struct ques{int l,r,id,t;}Q[maxn];
int ans[maxn];
int block[maxn];
bool operator <(const ques&a,const ques&b){
	if(block[a.l]!=block[b.l])return block[a.l]<block[b.l];
	if(block[a.r]!=block[b.r])return block[a.r]<block[b.r];
	return a.t<b.t;
}
int tot[1000010],nowans;
il vd fuck(int a,int b){
	if(tot[a]==1&&b==-1)--nowans;
	if(tot[a]==0&&b==1)++nowans;
	tot[a]+=b;
}
int main(){
#ifdef xzz
	freopen("1903.in","r",stdin);
	freopen("1903.out","w",stdout);
#endif
	int n=gi(),m=gi(),k=0,q=0,blo=pow(n,0.67),a,b;
	char o[2];
	for(rg int i=1;i<=n;++i)A[i]=gi();
	for(rg int i=1;i<=n;++i)block[i]=i/blo;
	for(rg int i=1;i<=m;++i){
		scanf("%s",o),a=gi(),b=gi();
		if(o[0]=='Q')++q,Q[q].l=a,Q[q].r=b,Q[q].id=q,Q[q].t=k;
		else if(o[0]=='R')++k,p[k]=a,pa[k]=A[a],A[a]=pb[k]=b;
	}
	std::sort(Q+1,Q+q+1);
	int L=1,R=1,T=k;
	tot[A[1]]=1;nowans=1;
	for(rg int i=1;i<=q;++i){
		while(T<Q[i].t){
			++T,A[p[T]]=pb[T];
			if(L<=p[T]&&p[T]<=R)fuck(pa[T],-1),fuck(pb[T],1);
		}
		while(T>Q[i].t){
			A[p[T]]=pa[T];
			if(L<=p[T]&&p[T]<=R)fuck(pb[T],-1),fuck(pa[T],1);
			--T;
		}
		while(L>Q[i].l)--L,fuck(A[L],1);
		while(R>Q[i].r)fuck(A[R],-1),--R;
		while(R<Q[i].r)++R,fuck(A[R],1);
		while(L<Q[i].l)fuck(A[L],-1),++L;
		ans[Q[i].id]=nowans;
	}
	for(rg int i=1;i<=q;++i)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2018-04-08 22:29  菜狗xzz  阅读(242)  评论(0编辑  收藏  举报