【bzoj 2120】 数颜色

3 篇文章 0 订阅

Description

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

Input

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

Output

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

Sample Input

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

Sample Output

4
4
3
4

HINT

 

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

这道题可以用带修改的莫队解决,带修改莫队是在普通莫队上加一维时间,排序时在块和右端点相同时比较询问时间,带修改莫队中的块大小为n^{\frac{2}{3}},复杂度为O(n^{\frac{5}{3}}),下面是程序:

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#define Q(n) (int)(n*1.0/m+0.999999)
using namespace std;
const int N=50005;
struct question{
	int l,r,i,q,s,t;
	bool operator <(const question &p)const{
		return q==p.q?r==p.r?t<p.t:q&1?r<p.r:r>p.r:q<p.q;
	}
}x[N];
struct cha{
	int i,x,y,l;
}y[N];
int n,m,q,s,a[N],k,p,t[1000005];
inline void read(int &s){
	s=0;
	char c=getchar();
	while(!isdigit(c)){
		c=getchar();
	}
	while(isdigit(c)){
		s=(s<<3)+(s<<1)+c-'0';
		c=getchar();
	}
}
bool cmp(question a,question b){
	return a.i<b.i;
}
char ch(){
	char c=getchar();
	while(c!='Q'&&c!='R'){
		c=getchar();
	}
	return c;
}
void add(int x){
	s+=!t[x];
	++t[x];
}
void del(int x){
	--t[x];
	s-=!t[x];
}
int main(){
	int i,l,r,ti;
	read(n),read(q);
	m=pow(n,2.0/3);
	for(i=1;i<=n;i++){
		read(a[i]);
	}
	for(i=1;i<=q;i++){
		if(ch()=='Q'){
			++k;
			read(x[k].l),read(x[k].r);
			x[k].q=Q(x[k].l);
			x[k].i=i;
			x[k].t=p;
			x[k].s=0;
		}
		else{
			++p;
			y[p].i=i;
			read(y[p].x),read(y[p].y);
			y[p].l=a[y[p].x];
			a[y[p].x]=y[p].y;
		}
	}
	for(i=p;i>=1;i--){
		a[y[i].x]=y[i].l;
	}
	y[p+1].i=1<<30;
	sort(x+1,x+k+1);
	l=r=ti=0;
	for(i=1;i<=k;i++){
		while(r<x[i].r){
			add(a[++r]);
		}
		while(r>x[i].r){
			del(a[r--]);
		}
		while(l<x[i].l){
			del(a[l++]);
		}
		while(l>x[i].l){
			add(a[--l]);
		}
		while(ti<x[i].t){
			++ti;
			if(y[ti].x>=l&&y[ti].x<=r){
				del(y[ti].l);
				add(y[ti].y);
			}
			a[y[ti].x]=y[ti].y;
		}
		while(ti>x[i].t){
			if(y[ti].x>=l&&y[ti].x<=r){
				del(y[ti].y);
				add(y[ti].l);
			}
			a[y[ti].x]=y[ti].l;
			--ti;
		}
		x[i].s=s;
	}
	sort(x+1,x+k+1,cmp);
	for(i=1;i<=k;i++){
		printf("%d\n",x[i].s);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值