P1903 [国家集训队]数颜色 / 维护队列
题目描述
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。
为了满足墨墨的要求,你知道你需要干什么了吗?
输入输出格式
输入格式:
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。
第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。
第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
输出格式:
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
输入输出样例
输入样例#1: 复制
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
输出样例#1: 复制
4
4
3
4
说明
对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
本题可能轻微卡常数
带修莫队和普通莫队的区别在于多加了一个时间 多了俩个时间的while
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
int Be[maxn],col[maxn],x,y,n,m,color[maxn*100],Ans[maxn],ans,l=1,r,T,unit,t,Time,now[maxn];
char sign;
struct node
{
int l,r,Tim,ID,sum;
} q[maxn];
struct aa
{
int pos,New,Old;
} c[maxn];
bool cmp(node a,node b)
{
return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.Tim<b.Tim:a.r<b.r):a.l<b.l;
}//分块排序
bool Cmp(node x,node y)
{
return x.ID<y.ID;
}//按id大小排序 准备输出
void revise(int x,int d)
{
if(color[x]!=0) ans--;//只有在这个颜色有的时候才消去一下影响
color[x]+=d;
if(color[x]!=0) ans++;//只有在这个颜色有的时候才加上影响
}
void gogoing(int x,int d)
{
if(l<=x&&x<=r)//如果更新时间的时候这个点在要求区间中
{
revise(d,1);//加上d
revise(col[x],-1);//消去col[x];
}
col[x]=d;//更改
}
int main()
{
scanf("%d%d",&n,&m);
unit=pow(n,0.666666);//最优分块方法
for(int i=1; i<=n; i++)
{
scanf("%d",&col[i]);
Be[i]=i/unit+1;
now[i]=col[i];
}
for(int i=1; i<=m; i++)
{
scanf(" %c %d%d",&sign,&x,&y);
if(sign=='Q')
{
q[++t]=(node)
{
x,y,Time,t
};//存数
}
if(sign=='R')
{
c[++Time]=(aa)
{
x,y,now[x]
};
now[x]=y;
}//存数
}
sort(q+1,q+t+1,cmp);
for(int i=1; i<=t; i++)
{
//按时间和左右边界进行美丽的暴力
while(T<q[i].Tim) gogoing(c[T+1].pos,c[T+1].New),T++;
while(T>q[i].Tim) gogoing(c[T].pos,c[T].Old),T--;
while(l<q[i].l)revise(col[l],-1),l++;
while(l>q[i].l)revise(col[l-1],1),l--;
while(r<q[i].r)revise(col[r+1],1),r++;
while(r>q[i].r)revise(col[r],-1),r--;
q[i].sum=ans;//存答案
}
sort(q+1,q+t+1,Cmp);
for(int i=1; i<=t; i++)
{
printf("%d\n",q[i].sum);
}
return 0;
}