【bzoj2120: 数颜色】带修改莫队

2120: 数颜色

Time Limit: 6 Sec   Memory Limit: 259 MB
Submit: 6501   Solved: 2593
[ Submit][ Status][ Discuss]

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。




刚开始忘了莫队有个排序,,就直接暴力了,没想到就过了,后来发现别人跑的比我的快很多,就想起来了。。。。

我们把修改操作和查询操作分开来,莫队一样莫队,我们在查询的时候判断这个查询前面本来有多少个修改操作(一个查询操作前的修改操作都是会影响当次查询操作的),可以同莫队类似的操作,如果还有没操作的修改就修改,如果修改的多了就回撤回去。

由于我们有三个关键字,我们按照 l.block r.block time 这三个关键字顺序排序,然后正常莫队就好了。

为什么要这样排,我也不大清楚,据说这样可以保证复杂度在O(n^(5/3))以内。这题数据水,暴力也没压力。

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 1000005
using namespace std;
int n,m,L,R,l,r,c[N],num[N],Num,cnt,cnt1,point;
int ans[10005],sz,vis[10005];
char ch[2];
struct he{
	int l,r,d,p,num,lst,l1,r1;
}q[10005],q1[10005];
bool cmp(he a,he b){
	if(a.l1==b.l1){
		if(a.r1==b.r1) return a.num<b.num;
		return a.r1<b.r1;
	}	
	return a.l1<b.l1;
}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	L=1;R=0;
	sz=sqrt(n)+1;
	for(int i=1;i<=m;i++){
		scanf("%s%d%d",ch,&l,&r);
		if(ch[0]=='Q'){
			cnt++;
			q[cnt].l=l;q[cnt].r=r;q[cnt].num=cnt1;q[cnt].p=cnt;
			q[cnt].l1=(l-1)/sz;q[cnt].r1=(r-1)/sz;
		}
		else {
			cnt1++;
			q1[cnt1].l=l;q1[cnt1].r=r;
		}
	}
	sort(q+1,q+1+cnt,cmp);
	
	point=0;
	for(int i=1;i<=cnt;i++){
		int l=q[i].l,r=q[i].r;
			while(R<r) {
				R++;
				num[c[R]]++;
				if(num[c[R]]==1) Num++;
			}
			while(R>r){
				num[c[R]]--;
				if(num[c[R]]==0) Num--;
				R--;
			}
			while(L>l){
				L--;
				num[c[L]]++;
				if(num[c[L]]==1) Num++;
			}
			while(L<l){
				num[c[L]]--;
				if(num[c[L]]==0) Num--;
				L++;
			}
			while(point<q[i].num){
				point++;
				if(L<=q1[point].l&&q1[point].l<=R){
					num[c[q1[point].l]]--;
					if(num[c[q1[point].l]]==0) Num--;
					num[q1[point].r]++;
					if(num[q1[point].r]==1) Num++;
				}
				q1[point].lst=c[q1[point].l];
				c[q1[point].l]=q1[point].r;
			}
			while(point>q[i].num){
				if(L<=q1[point].l&&q1[point].l<=R){
					num[q1[point].r]--;
					if(num[q1[point].r]==0) Num--;
					num[q1[point].lst]++;
					if(num[q1[point].lst]==1) Num++;			
				}
				c[q1[point].l]=q1[point].lst;
				point--;
			}
			ans[q[i].p]=Num;
	}
	for(int i=1;i<=cnt;i++)
		printf("%d\n",ans[i]);
}


猜你喜欢

转载自blog.csdn.net/bingoo0o0o/article/details/78741468