题目链接:Problem - 940F - Codeforces
题意:
一看是一个离散的区间查询带修改问题就知道可以用带修莫队来解决。
我们开一个cnt数组记录当前值出现的次数,再记录一个count数组来记录出现次数相同的值出现的次数(听起来有些绕哈,结合题意思考一下就知道是什么意思了),下面就是正常的带修莫队了,对于求mex我们是用暴力求得的。仔细观察一下数据范围,发现需要用到离散化,其他就是一个正常的带修莫队了,下面上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<vector>
using namespace std;
const int N=1e6+10;
int a[N],sum[N],cnt[N],Count[N],clock[N];
struct node{
int l,r,t,id;
}p[N];
//带修莫队中左右区间都要分块
bool cmp(node a,node b)
{
if(clock[a.l]!=clock[b.l]) return clock[a.l]<clock[b.l];
if(clock[a.r]!=clock[b.r]) return clock[a.r]<clock[b.r];
return a.t<b.t;
}
struct Node{
int pos,val;
}q[N];
map<int,int>mp;
void add(int x)
{
Count[cnt[x]]--;
cnt[x]++;
Count[cnt[x]]++;
}
void sub(int x)
{
Count[cnt[x]]--;
cnt[x]--;
Count[cnt[x]]++;
}
void change(int i,int j)
{
if(p[i].l<=q[j].pos&&q[j].pos<=p[i].r)
{
sub(a[q[j].pos]);
add(q[j].val);
}
swap(a[q[j].pos],q[j].val);
}
//离散化数组
vector<int>alls;
//离散化函数
int find(int x)
{
return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
int main()
{
int n,m;
cin>>n>>m;
int pl=max(1,(int)pow(n,2.0/3.0));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
alls.push_back(a[i]);//将数组初始值加入待离散化数组
clock[i]=(i-1)/pl+1;
}
int cntq=0,cntc=0,op,x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
cntq++;
p[cntq].l=x;
p[cntq].r=y;
p[cntq].t=cntc;
p[cntq].id=cntq;
}
else
{
cntc++;
q[cntc].pos=x;
q[cntc].val=y;
alls.push_back(y);//将修改后的值也加入待离散化数组
}
}
//离散化
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
for(int i=1;i<=n;i++)//将原数组的值变为其离散化后的值,防止数组存不下
a[i]=find(a[i]);
for(int i=1;i<=cntc;i++)//将修改后的值变为其离散化后的值,防止数组存不下
q[i].val=find(q[i].val);
sort(p+1,p+cntq+1,cmp);
int l=1,r=0,t=0;
for(int i=1;i<=cntq;i++)
{
while(l<p[i].l) sub(a[l++]);
while(l>p[i].l) add(a[--l]);
while(r<p[i].r) add(a[++r]);
while(r>p[i].r) sub(a[r--]);
while(t<p[i].t) change(i,++t);
while(t>p[i].t) change(i,t--);
int ans=1;
while(Count[ans]) ans++;//暴力求得目标区间的mex
sum[p[i].id]=ans;
}
for(int i=1;i<=cntq;i++)
printf("%d\n",sum[i]);
return 0;
}