[带修莫队]数颜色

BZOJ2120

带修莫队的做法:
把所有修改也离线下来
新建一个tk指针表示进行了k次修改,然后对于每个询问记录一下它之前有多少次修改,记为k,处理这个询问时如果当前修改次数小于k,那么就把tk往上滚,并进行修改,如果大于k,就把tk往下滚,并回溯修改

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=10005;
int pos[N],last[N];
int n,m,a[N],sqr;
int ans[N],cnt[N];
int cntq,cnto;
struct Q{int l,r,id,k;}q[N];
struct Op{int x,y,z;}op[N];
inline bool cmp(Q a,Q b){
	if(pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l];
	else if(pos[a.r]!=pos[b.r]) return pos[a.r]<pos[b.r];
	return a.k<b.k;
}
char ss;
int main(){
	n=read(),m=read();sqr=pow(n,2.0/3);
	for(int i=1;i<=n;i++) last[i]=a[i]=read();
	for(int i=1;i<=n;i++) pos[i]=(i-1)/sqr+1;
	for(int x,y,i=1;i<=m;i++){
		scanf("%c",&ss);x=read(),y=read();
		if(ss=='R') op[++cnto].x=x,op[cnto].y=y,op[cnto].z=last[x],last[x]=y;
		else q[++cntq].l=x,q[cntq].r=y,q[cntq].id=cntq,q[cntq].k=cnto;
	}
	sort(q+1,q+cntq+1,cmp);
	int tl=0,tr=0,tk=0,tot=0;
	for(int i=1;i<=cntq;i++){
		int l=q[i].l,r=q[i].r;
		while(tk<q[i].k){
			++tk;
			if(tl<=op[tk].x && op[tk].x<=tr){
				if(!--cnt[a[op[tk].x]]) --tot;
				if(!cnt[op[tk].y]++) ++tot;
			}
			a[op[tk].x]=op[tk].y;
		}
		while(tk>q[i].k){
			if(tl<=op[tk].x && op[tk].x<=tr){
				if(!--cnt[a[op[tk].x]]) --tot;
				if(!cnt[op[tk].z]++) ++tot;
			}
			a[op[tk].x]=op[tk].z;
			--tk;
		}
		while(tl<l) if(!--cnt[a[tl++]]) --tot;
		while(tl>l) if(!cnt[a[--tl]]++) ++tot;
		while(tr<r) if(!cnt[a[++tr]]++) ++tot;
		while(tr>r) if(!--cnt[a[tr--]]) --tot;
		ans[q[i].id]=tot;
	}
	for(int i=1;i<=cntq;i++) cout<<ans[i]<<'\n';
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值