您的位置:首页 > 其它

【P1903】【BZOJ2120】[国家集训队]数颜色 修改莫队

2018-03-26 19:29 381 查看

题目描述

墨墨购买了一套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

题解

这道题属于典型的带修改莫队。
[带修改莫队学习笔记](https://blog.csdn.net/nlt_xxy/article/details/79689896)


代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
const int MAXN=1e6;
using namespace std;
int block,Qnum,Cnum;
struct Query
{
int l,r,pre,Id;
friend bool operator < (Query A,Query B)
{
if(A.l/block==B.l/block) return A.r<B.r;
else return A.l/block<B.l/block;
}
}q[MAXN];
struct Change
{
int pos,num;
}c[MAXN];
int n,m,answer,ans[MAXN],val[MAXN],cnt[MAXN];
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void Add(int x)
{
if(++cnt[val[x]]==1) answer++;
}
inline void Remove(int x)
{
if(--cnt[val[x]]==0) answer--;
}
inline void Change_(int now,int x)
{
if(c[now].pos>=q[x].l&&c[now].pos<=q[x].r)
{
//cout<<"0";
if(--cnt[val[c[now].pos]]==0) answer--;
if(++cnt[c[now].num]==1) answer++;
}
swap(val[c[now].pos],c[now].num);//交换一下。
}
void Moque()
{
int nowl=1,nowr=0,now=0;
for(int i=1;i<=Qnum;i++)
{
while(nowl<q[i].l) Remove(nowl++);
while(nowl>q[i].l) Add(--nowl);
while(nowr<q[i].r) Add(++nowr);
while(nowr>q[i].r) Remove(nowr--);//普通莫队模板
while(now<q[i].pre) Change_(++now,i);//修改莫队模板
while(now>q[i].pre) Change_(now--,i);
//  cout<<now<<" ";
ans[q[i].Id]=answer;
}
for(int i=1;i<=Qnum;i++)
{
printf("%d\n",ans[i]);
}
return ;
}
int main()
{
scanf("%d%d",&n,&m);
block=n/sqrt(n*2/3);//传说中优化常数的方法
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1;i<=m;i++)
{
char opt[5];
scanf("%s",opt);
if(opt[0]=='Q')
{
q[++Qnum].l=read();
q[Qnum].r=read();
q[Qnum].pre=Cnum;//带修改莫队要记录离询问最近的修改
q[Qnum].Id=Qnum;
//  cout<<Qnum<<" ";
}
else if(opt[0]=='R')
{
c[++Cnum].pos=read();
c[Cnum].num=read();
}
}
//  cout<<Cnum;
//for(int i=1;i<=Qnum;i++) cout<<q[i].pre<<" ";
sort(q+1,q+Qnum+1);
Moque();
//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: