【国家集训队2011】数颜色 (莫队)

题面

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

【数据规模和约定】
对于40%数据,只包含第一类操作(无修改操作),且除此之外的20%的数据,N,M≤1000  对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。  时间限制:0.6s

题解

带修改莫队的模板题
(是不是数据比较水???)
看到两种AC做法
一种是对于每一次修改与修改之间的询问进行莫队计算,然后更新颜色,继续算答案直到下一次修改。
另一种是读入所有的询问,同普通莫队一样做,每次做之前更新颜色(记录当前的最后一次修改操作)。
我用的是第二种方法。

存颜色的修改的时候要存下修改成什么颜色以及原来的颜色(这个颜色也是会变的)
然后和普通莫队相差就不大了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 2000000
inline int read()
{
	register int x=0,t=1;
	register char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-'){t=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*t;
}
struct Query
{
	int l,r,id,t,ch;
}q[MAX];
struct Change
{
	int x,c,q;
}cc[MAX];
inline bool cmp(Query a,Query b)
{
	if(a.t==b.t)return a.r<b.r;
	return a.t<b.t;
}
int n,m,m1,m2,a[MAX],A[MAX],Ans=0;
int c[MAX],tot[MAX];
inline void change(int sw,int ne,int l,int r)
{
	if(sw==ne)return;
	if(sw<ne)
		for(int i=sw+1;i<=ne;++i)
		{
			if(cc[i].x<l||cc[i].x>r)c[cc[i].x]=cc[i].c;//直接修改
			else
			{
				tot[c[cc[i].x]]--;
				if(tot[c[cc[i].x]]==0)Ans--;
				tot[cc[i].c]++;
				if(tot[cc[i].c]==1)Ans++;
				c[cc[i].x]=cc[i].c;
			}
		}
	if(sw>ne)
		for(int i=sw;i>ne;--i)
		{
			if(cc[i].x<l||cc[i].x>r)c[cc[i].x]=cc[i].q;//直接修改
			else
			{
				tot[c[cc[i].x]]--;
				if(tot[c[cc[i].x]]==0)Ans--;
				tot[cc[i].q]++;
				if(tot[cc[i].q]==1)Ans++;
				c[cc[i].x]=cc[i].q;
			}
		}
}
inline void count(int p,int kk)
{
	tot[c[p]]+=kk;
	if(tot[c[p]]==0&&kk==-1)Ans--;
	if(tot[c[p]]==1&&kk==1 )Ans++;
}
int main()
{
    cin>>n>>m;
	int Len=sqrt(n);
	for(int i=1;i<=n;++i)cin>>a[i];
	for(int i=1;i<=n;++i)c[i]=a[i];
	for(int i=1;i<=m;++i)
	{
		char ch;int x,y;
		cin>>ch>>x>>y;
		if(ch=='Q')
		{
			m1++;
			q[m1]=(Query){x,y,m1,(x-1)/Len+1,m2};
		}
		else
		{
			m2++;
			cc[m2]=(Change){x,y,c[x]};
			c[x]=y;
		}
	}
	for(int i=1;i<=n;++i)c[i]=a[i];
	sort(&q[1],&q[m1+1],cmp);
	int l=1,r=0,sw=0;
	for(int i=1;i<=m1;++i)
	{
		if(sw!=q[i].ch)change(sw,q[i].ch,l,r);
		while(l<q[i].l)count(l-0,-1),l++;
		while(l>q[i].l)count(l-1,+1),l--;
		while(r<q[i].r)count(r+1,+1),r++;
		while(r>q[i].r)count(r+0,-1),r--;
		A[q[i].id]=Ans;
		sw=q[i].ch;
	}
	for(int i=1;i<=m1;++i)
		printf("%d\n",A[i]);
	return 0;
}

posted @ 2017-08-17 19:22  小蒟蒻yyb  阅读(331)  评论(0编辑  收藏  举报