2120: 数颜色
Time Limit: 6 Sec Memory Limit: 259 MBSubmit: 6501 Solved: 2593
[ Submit][ Status][ Discuss]
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
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
4
3
4
HINT
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
刚开始忘了莫队有个排序,,就直接暴力了,没想到就过了,后来发现别人跑的比我的快很多,就想起来了。。。。
我们把修改操作和查询操作分开来,莫队一样莫队,我们在查询的时候判断这个查询前面本来有多少个修改操作(一个查询操作前的修改操作都是会影响当次查询操作的),可以同莫队类似的操作,如果还有没操作的修改就修改,如果修改的多了就回撤回去。
由于我们有三个关键字,我们按照 l.block r.block time 这三个关键字顺序排序,然后正常莫队就好了。
为什么要这样排,我也不大清楚,据说这样可以保证复杂度在O(n^(5/3))以内。这题数据水,暴力也没压力。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 1000005
using namespace std;
int n,m,L,R,l,r,c[N],num[N],Num,cnt,cnt1,point;
int ans[10005],sz,vis[10005];
char ch[2];
struct he{
int l,r,d,p,num,lst,l1,r1;
}q[10005],q1[10005];
bool cmp(he a,he b){
if(a.l1==b.l1){
if(a.r1==b.r1) return a.num<b.num;
return a.r1<b.r1;
}
return a.l1<b.l1;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
L=1;R=0;
sz=sqrt(n)+1;
for(int i=1;i<=m;i++){
scanf("%s%d%d",ch,&l,&r);
if(ch[0]=='Q'){
cnt++;
q[cnt].l=l;q[cnt].r=r;q[cnt].num=cnt1;q[cnt].p=cnt;
q[cnt].l1=(l-1)/sz;q[cnt].r1=(r-1)/sz;
}
else {
cnt1++;
q1[cnt1].l=l;q1[cnt1].r=r;
}
}
sort(q+1,q+1+cnt,cmp);
point=0;
for(int i=1;i<=cnt;i++){
int l=q[i].l,r=q[i].r;
while(R<r) {
R++;
num[c[R]]++;
if(num[c[R]]==1) Num++;
}
while(R>r){
num[c[R]]--;
if(num[c[R]]==0) Num--;
R--;
}
while(L>l){
L--;
num[c[L]]++;
if(num[c[L]]==1) Num++;
}
while(L<l){
num[c[L]]--;
if(num[c[L]]==0) Num--;
L++;
}
while(point<q[i].num){
point++;
if(L<=q1[point].l&&q1[point].l<=R){
num[c[q1[point].l]]--;
if(num[c[q1[point].l]]==0) Num--;
num[q1[point].r]++;
if(num[q1[point].r]==1) Num++;
}
q1[point].lst=c[q1[point].l];
c[q1[point].l]=q1[point].r;
}
while(point>q[i].num){
if(L<=q1[point].l&&q1[point].l<=R){
num[q1[point].r]--;
if(num[q1[point].r]==0) Num--;
num[q1[point].lst]++;
if(num[q1[point].lst]==1) Num++;
}
c[q1[point].l]=q1[point].lst;
point--;
}
ans[q[i].p]=Num;
}
for(int i=1;i<=cnt;i++)
printf("%d\n",ans[i]);
}