bzoj 2120 数颜色 带修莫队

题解:

// Q L R询问 L到R区间不同颜色数
// R P col 将R位置的颜色改为col 
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1000005;//unit = n^(2/3)  O(n^(5/3))
struct Tim{int l,r,t,ID;}q[maxn];
struct Change{int pos,New,old;}c[maxn];
int n,m,l=1,r,Ans,unit,t,Time,T;
int s[maxn],color[maxn],Be[maxn],now[maxn],ans[maxn]; 
int cmp(Tim c,Tim d){
	return Be[c.l]==Be[d.l]?(Be[c.r]==Be[d.r]?c.t<d.t:c.r<d.r):c.l<d.l;
} 
void revise(int x,int d){//颜色x在区间值变化 d 指针移动 
	color[x]+=d; if(d>0)Ans+=(color[x]==1);if(d<0)Ans-=(color[x]==0); 
}
void going(int x,int d){//单点修改 x位置 变为 d  
	if(x<=r&&x>=l)revise(s[x],-1),revise(d,1);//l,r内改变,在l,r外下面while会改变 
	s[x] = d;
}
int main() {
	char op;
	int x,y;
	cin.tie(0);
	cin>>n>>m; unit = pow(n,0.6666);
	for(int i=1;i<=n;i++)cin>>s[i],now[i] = s[i],Be[i] = i/unit+1;
	for(int i=1;i<=m;i++){
		cin>>op>>x>>y;
		if(op=='Q')q[++t].l = x,q[t].r = y,q[t].t = Time,q[t].ID = t;//询问[x,y]区间不同颜色的笔有几只 
		if(op=='R')c[++Time].pos = x,c[Time].New = y,c[Time].old=now[x],now[x] = y;
		//Q是把第 x 只画笔颜色变为y 
	}
	sort(q+1,q+t+1,cmp);
	for(int i=1;i<=t;i++){
		while(T<q[i].t)going(c[T+1].pos,c[T+1].New),T++;//T代表现在的时间 
		while(T>q[i].t)going(c[T].pos,c[T].old),T--;
		
		while(l<q[i].l)revise(s[l],-1),l++;
		while(l>q[i].l)revise(s[l-1],1),l--;
		while(r<q[i].r)revise(s[r+1],1),r++;
		while(r>q[i].r)revise(s[r],-1),r--;
		ans[q[i].ID] = Ans;
	}
	for(int i=1;i<=t;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值