2120: 数颜色
Description
墨墨购买了一套 N N N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1 、 Q L R 1、 Q\ L\ R 1、Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2 、 R P C o l 2、 R\ P\ Col 2、R P Col 把第 P 4 支 画 笔 替 换 为 颜 色 P4支画笔替换为颜色 P4支画笔替换为颜色Col$。为了满足墨墨的要求,你知道你需要干什么了吗?
Input
第1行两个整数 N , M N,M N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第 2 2 2行 N N N个整数,分别代表初始画笔排中第i支画笔的颜色。第 3 3 3行到第 2 + M 2+M 2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
Output
对于每一个 Q u e r y Query Query的询问,你需要在对应的行中给出一个数字,代表第 L L L支画笔到第 R R R支画笔中共有几种不同颜色的画笔。
Sample Input
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
4
4
3
4
HINT
对于 100 % 100\% 100%的数据, N ≤ 10000 N\leq 10000 N≤10000, M ≤ 10000 M\leq 10000 M≤10000,修改操作不多于 1000 1000 1000次,所有的输入数据中出现的所有整数均大于等于 1 1 1且不超过 1 0 6 10^6 106。
题意
- 在普通的莫队典型例题:查询区间颜色种类数量的基础上,需要支持单点颜色修改操作
题解
- 带修莫队模版题
- 每个查询操作记录一个值表示前面有多少次修改,然后对于每一个修改,记录这个点修改前的颜色和修改后的颜色,方便加上这个颜色和撤销
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=10005; // max node
const int maxm=10005; // max operate/query
const int max_col=1000005; // max color
int ans[maxm],a[maxn]; //a:initial cilor
int block_size,block[maxn],numq,numo,color[maxn],num[max_col],res; //color临时存每个位置的颜色
struct query{ //numq:number of query numo:number of operate
int id,l,r,change; //num:每个颜色的数量
query(int a=0,int b=0,int c=0,int d=0) { //res:当前区间答案
id=a;l=b;r=c;change=d;
}
friend bool operator<(const query&a,const query&b){
if(block[a.l]^block[b.l]) return a.l<b.l;
if(block[a.r]^block[b.r]) return a.r<b.r;
return a.change<b.change;
}
}q[maxm];
struct operate{
int pos,pre,nxt; //pos记录修改的位置,pre为修改之前的数,nxt为修改后的数
operate(int a=0,int b=0,int c=0) {
pos=a;pre=b;nxt=c;
}
}o[maxm];
void init(int n)
{
numq=numo=0;
block_size=(int)pow(n,2.0/3);
for(int i=1;i<=n;i++) block[i]=i/block_size;
}
void add_change(int id,int l,int r)
{
if(o[id].pos>=l&&o[id].pos<=r) {
if(--num[a[o[id].pos]]==0) res--;
if(++num[o[id].nxt]==1) res++;
}
a[o[id].pos]=o[id].nxt;
}
void del_change(int id,int l,int r)
{
if(o[id].pos>=l&&o[id].pos<=r) {
if(--num[a[o[id].pos]]==0) res--;
if(++num[o[id].pre]==1) res++;
}
a[o[id].pos]=o[id].pre;
}
void add(int id)
{
if(++num[a[id]]==1) res++;
}
void del(int id)
{
if(--num[a[id]]==0) res--;
}
void mo_dui()
{
int l=1,r=0,k=0; //k为前缀修改数量
for(int i=1;i<=numq;i++) {
while(k<q[i].change) add_change(++k,l,r);
while(k>q[i].change) del_change(k--,l,r);
while(l<q[i].l) del(l++);
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(r>q[i].r) del(r--);
ans[q[i].id]=res;
}
}
int n,m,x,y;
char opt[10];
int main()
{
scanf("%d %d",&n,&m);init(n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),color[i]=a[i];
for(int i=1;i<=m;i++) {
scanf("%s %d %d",opt+1,&x,&y);
if(opt[1]=='Q') q[numq+1]=query(numq+1,x,y,numo),numq++;
else o[++numo]=operate(x,color[x],y),color[x]=y;
}
sort(q+1,q+numq+1);
mo_dui();
for(int i=1;i<=numq;i++) printf("%d\n",ans[i]);
}