带修改莫队/【2011集训队出题】数颜色

防遗忘故作此文

1.待修改莫队

普通莫队不支持修改,要支持修改,需在原有基础上增加一维:时间。

时间变更而修改时,直接在数组修改;特殊地,如其位置在区间内需要add,del操作。

2.例题:数颜色

题意:一个序列,支持修改一个位置的颜色+查询区间颜色数,可离线。

思路:与1中内容如出一辙。

code:

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define inf 1000000007
using namespace std;
int n,m,l1,l2,lst[1000005],sq,ans,sum[1000005];
int bz[1000005],a[1000005],c[1000005];
int l,r,t;
struct query
{
	int a,b,id,t;
}Q[1000005];
struct change
{
	int a,pre,nxt;
}R[1000005];
long long read()
{
	long long x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
	return x*f;
}
bool cmp(query a,query b)
{
	if(a.a/sq==b.a/sq)
	{
		if(a.b/sq==b.b/sq)return a.id<b.id;
		return a.b<b.b;
	}
	return a.a<b.a;
}
void add(int x)
{
	if(!bz[x])ans++;
	bz[x]++;
}
void del(int x)
{
	bz[x]--;
	if(!bz[x])ans--;
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();lst[i]=a[i];c[i]=a[i];
	}
	sq=sqrt(n);
	for(int i=1,x,y;i<=m;i++)
	{
		
		char ch=getchar();
		while(ch!='Q'&&ch!='R')ch=getchar();
		x=read(),y=read();
		if(ch=='Q') Q[++l1].a=x,Q[l1].b=y,Q[l1].id=l1,Q[l1].t=l2;
		else R[++l2].a=x,R[l2].pre=lst[x],R[l2].nxt=y,lst[x]=y;
	}
	sort(Q+1,Q+l1+1,cmp);
	l=1,r=0;
	for(int i=1,j=0;i<=l1;i++)
	{
		for(;j<Q[i].t;j++)
		{
			if(l<=R[j+1].a&&R[j+1].a<=r)del(R[j+1].pre),add(R[j+1].nxt);
			c[R[j+1].a]=R[j+1].nxt;
		}
		for(;j>Q[i].t;j--)
		{
			if(l<=R[j].a&&R[j].a<=r)del(R[j].nxt),add(R[j].pre);
			c[R[j].a]=R[j].pre;
		}
		while(r<Q[i].b)add(c[++r]);
		while(r>Q[i].b)del(c[r--]);
		while(l<Q[i].a)del(c[l++]);
		while(l>Q[i].a)add(c[--l]);
		sum[Q[i].id]=ans;
	}
	for(int i=1;i<=l1;i++)
	{
		printf("%d\n",sum[i]);
	}
	return 0;
} 

3.感谢OI Wiki

 

posted @ 2021-11-10 21:32  HYDcn666_JZOJ  阅读(29)  评论(0编辑  收藏  举报