CF940F Machine Learning

题目描述

给你一个数组\(\{a_i\}\)支持两种操作:

  1. 查询区间\([l,r]\)中每个数字出现次数的mex。

  2. 单点修改某一个位置的值。

mex指的是一些数字中最小的未出现的自然数。值得注意的是,区间\([l,r]\)总有数字是没有出现过的,所以答案不可能为0.

\(\large n,Q\le10^5\)

样例 #1

样例输入 #1

10 4
1 2 3 1 1 2 2 2 9 9
1 1 1
1 2 8
2 7 1
1 2 8

样例输出 #1

2
3
2

分析

首先考虑如何区间求 mex:

已知带修莫队的时间复杂度为 \(\large O(n^{\frac{3}{5}})\),考虑答案为 \(x\)

那么存在出现了 \(1\) 次的数,\(2\) 次的数......出现了 \(x-1\) 次的数,所以 \(\large\Sigma_{i=1}^{x-1} i\leq n\),所以说答案是 \(O(\sqrt{n})\) 级别的,所以暴力求 mex 不会影响总时间复杂度。那么直接跑一遍带修莫队即可。

注意将数据离散化。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch&15);ch=getchar();}
	return x*f;
}
int n,m,qnum,cnum,a[200005],pos[200005],bl,cnt,b[200005],tot[200005],ans[200005],num[200005];
struct node{
	int l,r,t,id;
}q[200005];
struct ch{
	int p,pos;
}c[200005];
bool cmp(node x,node y){return pos[x.l]^pos[y.l]?x.l<y.l:(pos[x.r]^pos[y.r]?x.r<y.r:x.t<y.t);}
void add(int x){--tot[num[x]],++tot[++num[x]];}
void del(int x){--tot[num[x]],++tot[--num[x]];}
void change(int t,int qq){
	if(c[t].pos>=q[qq].l&&c[t].pos<=q[qq].r)del(a[c[t].pos]),add(c[t].p);
	swap(a[c[t].pos],c[t].p);
}
signed main(){
	n=read(),m=read();bl=pow(n,2.0/3.0);
	for(int i=1;i<=n;i++)b[++cnt]=a[i]=read(),pos[i]=(i-1)/bl+1;
	for(int i=1,opt;i<=m;i++){
		opt=read();
		if(opt==1){
			q[++qnum].l=read(),q[qnum].r=read();
			q[qnum].t=cnum,q[qnum].id=qnum;
		}else{
			c[++cnum].pos=read(),c[cnum].p=read();
			b[++cnt]=c[cnum].p;
		}
	}
	sort(q+1,q+qnum+1,cmp);
	sort(b+1,b+cnt+1);
	cnt=unique(b+1,b+cnt+1)-b;
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
	for(int i=1;i<=cnum;i++)c[i].p=lower_bound(b+1,b+cnt+1,c[i].p)-b;
	for(int i=1,l=1,r=0,now=0;i<=qnum;i++){
		while(q[i].l<l)add(a[--l]);
		while(q[i].r>r)add(a[++r]);
		while(q[i].l>l)del(a[l++]);
		while(q[i].r<r)del(a[r--]);
		while(now<q[i].t)change(++now,i);
		while(now>q[i].t)change(now--,i);
		for(ans[q[i].id]=1;tot[ans[q[i].id]];ans[q[i].id]++);
	}
	for(int i=1;i<=qnum;i++)printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2023-06-24 14:18  alex_liu09  阅读(10)  评论(0)    收藏  举报