【BZOJ2120】—数颜色(带修莫队)

传送门

带修莫队版题

记录多记一维是第几次修改,记录一下修改之前是什么颜色就可以了

块大小不能开 n \sqrt n n ,那样复杂度没有变化

大概 n 2 3 n^{\frac 2 3} n32或者 n 3 4 n^{\frac 3 4} n43的时候最优

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=10005,M=1000005;
int blo,plc[N],col[N],n,m;
struct ask{
	int l,r,t,idx;
	friend inline bool operator <(const ask &a,const ask &b){
		if(plc[a.l]!=plc[b.l])return plc[a.l]<plc[b.l];
		if(plc[a.r]!=plc[b.r])return plc[a.r]<plc[b.r];
		return a.t<b.t;
	}
}p[N];
struct upd{
	int x,y,z;
}q[N];
int buc[M],now,tim,qt,ans[N];
int l,r,t;
inline void add(int p){
	if(!buc[col[p]])now++;
	buc[col[p]]++;
}
inline void del(int p){
	buc[col[p]]--;
	if(!buc[col[p]])now--;
}
inline void in(int i){
	int p=q[i].x,to=q[i].y,&fr=q[i].z;
	if(p>=l&&p<=r)del(p);
	fr=col[p];
	col[p]=to;
	if(p>=l&&p<=r)add(p);
}
inline void out(int i){
	int p=q[i].x,to=q[i].y,fr=q[i].z;
	if(p>=l&&p<=r)del(p);
	col[p]=fr;
	if(p>=l&&p<=r)add(p);
}
inline void solve(){
	l=1,r=0,t=0;
	for(int i=1;i<=qt;i++){
		while(r<p[i].r)add(++r);
		while(r>p[i].r)del(r--);
		while(l<p[i].l)del(l++);
		while(l>p[i].l)add(--l);
		while(t<p[i].t)in(++t);
		while(t>p[i].t)out(t--);
		ans[p[i].idx]=now;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)col[i]=read();
	blo=sqrt(sqrt(n)),blo=blo*blo*blo;
	for(int i=1;i<=n;i++)plc[i]=(i-1)/blo+1;
	char op[3];
	for(int i=1;i<=m;i++){
		scanf("%s",op);
		int x=read(),y=read();
		if(op[0]=='Q')p[++qt]=(ask){x,y,tim,qt};
		else q[++tim]=(upd){x,y,0};
	}
	sort(p+1,p+qt+1);
	solve();
	for(int i=1;i<=qt;i++)cout<<ans[i]<<'\n';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值