2120: 数颜色
Time Limit: 6 Sec Memory Limit: 259 MB
Submit: 7556 Solved: 3071
[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
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
题目:BZOJ2120
思路:莫队算法,带修改。
对于带修改莫队的实现:
1.在普通莫队的基础上,增加第三关键字为更新时间,即询问最近一次更新之后
2.增加更新函数和更新记录指针,对于每次询问,如果更新小于当前询问,先暴力更新,并维护答案,然后是普通更新的过程
AC代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define met(s,k) memset(s,k,sizeof s)
#define scan(a) scanf("%d",&a)
#define scanl(a) scanf("%lld",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannl(a,b) scanf("%lld%lld",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define prin(a) printf("%d\n",a)
#define prinl(a) printf("%lld\n",a)
using namespace std;
typedef long long ll;
const int maxn=2e6+10;
int n,m,unit,ans,ans1[maxn],cont;
int currenl,currenr,time;
struct que
{
int l,r,pos,cont/*第三关键字,更新戳*/;
}q[maxn];
struct upd
{
int pos,inter;
}up[maxn];
bool cmp(que a,que b)
{
int x=a.l/unit;
int y=b.l/unit;
if(x!=y)return x<y;
else if(a.r!=b.r) return a.r<b.r;
else return a.cont<b.cont;
}
int a[maxn],vis[maxn];
void removeposx(int pos)
{
if(--vis[a[pos]]==0)ans--;
}
void addposx(int pos)
{
if(++vis[a[pos]]==1)ans++;
}
void update(int time)//更新函数
{
if(up[time].pos>=currenl&&up[time].pos<=currenr)//只有更新位置在当前区间内,才会对答案有影响
{
if(++vis[up[time].inter]==1)ans++;
if(--vis[a[up[time].pos]]==0)ans--;
}
swap(a[up[time].pos],up[time].inter);//每次更新过后,如果我们要把它更新回来的话,就要把它改到更新之前的值,这个值不一定是最初的数组,所以我们要记下更新之前的值,这里直接交换一下就可以了
}
void modui(int m)
{
for (int i = 0; i <m; ++i)
{
while (currenr<q[i].r)addposx(++currenr);
while (currenr>q[i].r)removeposx(currenr--);
while (currenl<q[i].l)removeposx(currenl++);
while (currenl>q[i].l)addposx(--currenl);
while (time<q[i].cont)update(++time);//更新可以放在前面,也可以在后面
while (time>q[i].cont)update(time--);
ans1[q[i].pos]=ans;
}
}
int main()
{
scann(n,m);
int quest=0;
currenl=1,currenr=0,time=0/*更新时间戳*/;
met(vis,0);
unit=(int)sqrt((double)n);
for(int i=1;i<=n;i++)scan(a[i]);
for(int i=0;i< m;i++)
{
char c;
int x,y;
scanf(" %c%d%d",&c,&x,&y);
if(c=='Q')
{
q[quest].l=x;
q[quest].r=y;
q[quest].pos = quest;
q[quest++].cont=cont;
}
if(c=='R')
{
up[++cont].pos=x;
up[cont].inter=y;
}
}
sort(q,q+quest,cmp);
modui(quest);
for (int j = 0; j <quest; ++j)prin(ans1[j]);
return 0;
}