CodeForces - 940F 带单点修改的莫队
带单点修改的莫队
众所周知莫队处理的区间不可以修改,因为要离线排序暴力答案,如果中途有修改的话,排序前后区间不同,答案也就是错的,如果要使答案正确的话还需要将时间统一,例如上次计算的答案在某次修改之后的区间,而这次在修改之前,那么就要回到过去,取消修改的影响,反之相反。
难点就在这啦,按照普通莫队,每次都要统一时间的话时间复杂度会多一维,必然超时。大佬们想出了一种办法去优化,就是用二维莫队,如每次询问 l , r 区间,在 l 分块的基础上再把 r 分块,在多一维的p按从小到大顺序,暴力方法就是上一段说的,大佬们说这个的时间复杂度大约是 n^5/3左右,还是很厉害的。
然后就是一些细节
1.分块的大小为总数2/3次方,一般莫队为1/2。
2.带修改操作需要离散化和记录数量的点会变多,最好数组开原来的两倍。
3.记录被修改的点的前值与后值时,如果有多次在同一位置,记录的两个点应是上一次修改被改为的值与这次修改后的值,而不是a[p]与这次修改后的值。(a数组指给你的区间的值,长度为n的那个)
4.在记录时如改变了a数组的值,需要记录完后改回去,因为一般时间从0开始。
5.排序规则对 l , r 分块排序,对时间正常排。
这些细节都是我惨痛教训。
题意:给一个长度n数组,a数组记录值,q次操作,两种操作,一种修改a+p位置的值,一种算 l , r 区间的值的个数的mex(mex指,如果有s个相等的数,那s是好的,然后你要输出最小的不好的。如mex=3,说明区间内有相等的数的个数为1的存在,为2的存在,为3的不存在)。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,q,ans[200007],a[200007],b[200007],l,r,z,size,head,maze,ak[200007],num[200007],cnt[200007];
vector<int>lsh,qans;
struct madoka{
int l;
int r;
int p;
}ho[200007],lin;
vector<madoka>ma;
bool cmp(madoka a1,madoka a2){
if(ak[a1.l]==ak[a2.l]){
if(ak[a1.r]==ak[a2.r]){
return a1.p<a2.p;
}
return ak[a1.r]<ak[a2.r];
}
return ak[a1.l]<ak[a2.l];
}
void dis(){
sort(lsh.begin(),lsh.end());
lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
for(int i=1;i<=n;i++){
a[i]=lower_bound(lsh.begin(),lsh.end(),a[i])-lsh.begin()+1;
}
for(int i=1;i<=q;i++){
if(ho[i].p!=0){
ho[i].l=lower_bound(lsh.begin(),lsh.end(),ho[i].l)-lsh.begin()+1;
ho[i].r=lower_bound(lsh.begin(),lsh.end(),ho[i].r)-lsh.begin()+1;
}
}
}
void go(){
l=1,r=1;
int p=0;
cnt[num[a[r]]]--;
num[a[r]]++;
cnt[num[a[r]]]++;
for(int i=0;i<ma.size();i++){
while(r<ma[i].r){
r++;
cnt[num[a[r]]]--;
num[a[r]]++;
cnt[num[a[r]]]++;
}
while(r>ma[i].r){
cnt[num[a[r]]]--;
num[a[r]]--;
cnt[num[a[r]]]++;
r--;
}
while(l<ma[i].l){
cnt[num[a[l]]]--;
num[a[l]]--;
cnt[num[a[l]]]++;
l++;
}
while(l>ma[i].l){
l--;
cnt[num[a[l]]]--;
num[a[l]]++;
cnt[num[a[l]]]++;
}
while(p<ma[i].p){
p++;
if(ho[p].p==0)continue;
if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
cnt[num[ho[p].l]]--;
num[ho[p].l]--;
cnt[num[ho[p].l]]++;
cnt[num[ho[p].r]]--;
num[ho[p].r]++;
cnt[num[ho[p].r]]++;
}
a[ho[p].p]=ho[p].r;
}
while(p>ma[i].p){
if(ho[p].p==0){
p--;
continue;
}
if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
cnt[num[ho[p].l]]--;
num[ho[p].l]++;
cnt[num[ho[p].l]]++;
cnt[num[ho[p].r]]--;
num[ho[p].r]--;
cnt[num[ho[p].r]]++;
}
a[ho[p].p]=ho[p].l;
p--;
}
for(int j=1;j<=n;j++){
if(cnt[j]==0){
ans[ma[i].p]=j;
break;
}
}
}
}
int main(){
scanf("%d%d",&n,&q);
size=(int)pow(n,2.0/3.0);
maze=ceil((double)n/size);
for(int i=1;i<=maze;i++){
for(int j=head;j<head+size&&j<=n;j++){
ak[j]=i;
}
head+=size;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
lsh.push_back(a[i]);
}
for(int i=1;i<=q;i++){
scanf("%d%d%d",&z,&l,&r);
if(z==1){
lin.l=l;
lin.r=r;
lin.p=i;
ma.push_back(lin);
qans.push_back(i);
}
else{
lin.l=a[l];
lin.r=r;
lin.p=l;
ho[i]=lin;
a[l]=r;
lsh.push_back(r);
}
}
for(int i=1;i<=n;i++)a[i]=b[i];
dis();
sort(ma.begin(),ma.end(),cmp);
go();
for(int i=0;i<qans.size();i++){
printf("%d\n",ans[qans[i]]);
}
}