bzoj 2120: 数颜色【带修改莫队】

比较裸的带修莫队,对每个修改操作记一下它修改的位置修改前的颜色
然后正常莫队,每次对修改操作时间倒流一下即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
int n,m,bl[N],la[N],co[1000005],ta,tb,v[N],con[1000005],ans[N],nw;
char s[10];
struct qw
{
	int p,c,pr;
}a[N];
struct qwe
{
	int l,r,id,ti;
}b[N];
bool cmp(const qwe &a,const qwe &b)
{
	return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);
}
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void clc(int x)
{
	if(v[x])
	{
		if(!--con[co[x]])
			nw--;
	}
	else if(++con[co[x]]==1)
		nw++;
	v[x]^=1;
}
void change(int x,int c)
{
	if(v[x])
	{
		clc(x);
		co[x]=c;
		clc(x);
	}
	else
		co[x]=c;
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		la[i]=co[i]=read();
	for(int i=1;i<=m;i++)
	{
		scanf("%s",s);
		int x=read(),y=read();
		if(s[0]=='R')
		{
			a[++ta].p=x;
			a[ta].c=y;
			a[ta].pr=la[x];//记录更改之前的颜色
			la[x]=y;
		}
		else
		{
			b[++tb].l=x;
			b[tb].r=y;
			b[tb].id=tb;
			b[tb].ti=ta;//记录他之前的离他最近的操作
		}
	}
	int kuai=sqrt(n);
	for(int i=1;i<=n;i++)
		bl[i]=(i-1)/kuai+1;
	sort(b+1,b+tb+1,cmp);
	int l=1,r=1;
	clc(l);
	for(int i=1;i<=tb;i++)
	{
		for(int j=b[i-1].ti+1;j<=b[i].ti;j++)
			change(a[j].p,a[j].c);
		for(int j=b[i-1].ti;j>b[i].ti;j--)
			change(a[j].p,a[j].pr);
		while(l<b[i].l)  
			clc(l++);
		while(l>b[i].l)  
			clc(--l);
		while(r<b[i].r)  
			clc(++r);
		while(r>b[i].r)  
			clc(r--);
		ans[b[i].id]=nw;
	}
	for(int i=1;i<=tb;i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2018-09-27 14:22  lokiii  阅读(152)  评论(0编辑  收藏  举报