题目描述
墨墨购买了一套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。
本题可能轻微卡常数
题解
- 带修改莫队裸题
```cppinclude
include
include
include
include
include
include
define in(i) (i=read())
using namespace std;
typedef long long lol;
lol read()
{
lol ans=0,f=1;
char i=getchar();
while(i<‘0‘||i>‘9‘)
{
if(i==‘-‘) f=-1;
i=getchar();
}
while(i>=‘0‘&&i<=‘9‘)
{
ans=(ans<<3)+(ans<<1)+i-‘0‘;
i=getchar();
}
return ans*f;
}
struct query
{
lol l,r,id,pos,pre;
}e[200010];
struct chang
{
lol pos,val;
}q[200010];
lol c[500010];
lol cnt[1000010];
lol ans[200010];
lol tot,qnum,cnum;
lol n,m;
lol cmp(query a,query b)
{
if(a.pos!=b.pos) return a.pos<b.pos;
if(a.r!=b.r) return a.r<b.r;
return a.pre<b.pre;
}
void add(lol x)
{
cnt[c[x]]++;
if(cnt[c[x]]==1) tot++;
}
void remove(lol x)
{
cnt[c[x]]--;
if(cnt[c[x]]==0) tot--;
}
void work(int now,int i)
{
if(q[now].pos>=e[i].l && q[now].pos<=e[i].r)
{
if(--cnt[c[q[now].pos]]==0) tot--;
if(++cnt[q[now].val]==1) tot++;
}
swap(q[now].val,c[q[now].pos]);
}
void solve()
{
for(lol i=1,curl=1,curr=0,now=0;i<=qnum;i++)
{
lol l=e[i].l,r=e[i].r;
while(curll) add(--curl);
while(currr) remove(curr--);
while(nowe[i].pre) work(now--,i);
ans[e[i].id]=tot;
}
for(lol i=1;i<=qnum;i++)
{
printf("%lld\n",ans[i]);
}
}
int main()
{
in(n);in(m);
lol block=(lol)sqrt(n);
for(lol i=1;i<=n;i++) in(c[i]);
for(lol i=1;i<=m;i++)
{
char ch;
cin>>ch;
if(ch==‘Q‘)
{
in(e[++qnum].l);in(e[qnum].r);
e[qnum].id=qnum;
e[qnum].pos=(e[qnum].l-1)/block+1;
e[qnum].pre=cnum;
}
else
{
in(q[++cnum].pos);in(q[cnum].val);
}
}
sort(e+1,e+1+qnum,cmp);
solve();
return 0;
}
```
原文地址:https://www.cnblogs.com/real-l/p/9210936.html