带修改莫队/【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