【bzoj2120】[国家集训队]数颜色[莫队]

[国家集训队]数颜色

P1903 国家集训队]数颜色 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;
}
posted @ 2019-09-06 14:58  委屈的咸鱼鱼鱼鱼  阅读(142)  评论(0编辑  收藏  举报