【题解】CF940F Machine Learning

Link

题目大意:单点修改,每次询问一个区间的所有颜色出现次数的\(\text{Mex}.\)

例如,区间中三种颜色分别出现了\(2,2,3\)次,又因为其他颜色出现次数一定是\(0\),所以这里的答案是\(1.\)

\(\text{Solution:}\)

这是带修莫队的一道题。

观察到,我们可以\(O(1)\)来更新一个颜色的出现次数,以及这个出现次数的次数。

套上带修莫队套路,每次按照三关键字排序,左,右,时间。时间是修改相关。每次我们更改一个颜色,就把原来的颜色删掉一个,新改的颜色加上一个就好了。

因为当块长为\(n^{\frac{2}{3}}.\)时,时间复杂度为\(n^{\frac{5}{3}}\).所以可以过。

下面是一些处理技巧:

对于颜色很大,观察到\(n,q\)不大,所以有用的颜色最多有\(n+q\)个,直接离散化即可。复杂度\(O(n\log n).\)

那么,每次答案怎么统计呢?

考虑暴力的方法。因为\(0\)一定不会是答案,所以我们从\(1\)开始枚举。考虑最长的枚举次数,设为\(x\).

那么有\(\frac{x*(x+1)}{2}\leq n\),就是出现次数从\(1\)加到\(x\).

那么:

\(x^2+x \leq 2n\),也就是说\(x\)也就\(\sqrt{n}\)的级别左右。

如果\(q\)次统计,那复杂度就是\(O(q\sqrt n).\)由于\(n,q\)同阶,而这个复杂度就是\(O(n^{\frac{3}{2}})\),小于\(O(n^{\frac{5}{3}}).\)所以复杂度有保证。

\(1e5\)的情况下这个复杂度还是可以的。在\(\text{O2}\)情况下跑的很优秀。一般的话这个复杂度算出来是\(O(10^{\frac{25}{3}})=O(10^{8.3333})\),卡时间限制可以过。

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int bl[MAXN],a[MAXN],n,m,siz,bnum;
int ans[MAXN],cnt[MAXN],mex[MAXN];
int cntq,cntc,A[MAXN],tot,L;
inline bool isdigit(char C){return C<='9'&&C>='0';}
struct Q{
	int l,r,t,id;
	bool operator<(const Q&B)const{
		return (bl[l]^bl[B.l])?bl[l]<bl[B.l]:(bl[r]^bl[B.r])?bl[r]<bl[B.r]:bl[t]<bl[B.t];
	}
}q[MAXN];
struct C{
	int pos,v;
}c[MAXN];
inline int read(){
	register int s=0;
	register char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>=10)write(x/10);
	putchar(x%10+48);
}
void del(int x){
	--mex[cnt[a[x]]];
	++mex[--cnt[a[x]]];
}
void add(int x){
	--mex[cnt[a[x]]];
	++mex[++cnt[a[x]]];
}
int Get(){
	int i;for(i=1;mex[i];++i);
	return i;
}
int main(){
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;++i)A[++tot]=read(),a[i]=A[tot];
	siz=pow(n,(double)2.0/3.0);
	bnum=ceil((double)n/siz);
	for(register int i=1;i<=bnum;++i)for(register int j=(i-1)*siz+1;j<=i*siz;++j)bl[j]=i;
	for(register int i=1;i<=m;++i){
		register int opt=read();
		if(opt==1){
			q[++cntq].t=cntc;
			q[cntq].id=cntq;
			q[cntq].l=read();
			q[cntq].r=read();
		}
		else{
			c[++cntc].pos=read();
			c[cntc].v=read();
			A[++tot]=c[cntc].v;
		}
	}
	sort(q+1,q+cntq+1);
	sort(A+1,A+tot+1);
	L=unique(A+1,A+tot+1)-A-1;
	for(register int i=1;i<=n;++i)a[i]=lower_bound(A+1,A+L+1,a[i])-A;
	for(register int i=1;i<=cntc;++i)c[i].v=lower_bound(A+1,A+L+1,c[i].v)-A;
	int l=1,r=0,tm=0;
	for(register int i=1;i<=m;++i){
		int ql=q[i].l,qr=q[i].r,qt=q[i].t;
		while(l<ql)del(l++);
		while(l>ql)add(--l);
		while(r<qr)add(++r);
		while(r>qr)del(r--);
		while(tm<qt){
			++tm;
			if(c[tm].pos>=ql&&c[tm].pos<=qr){
				del(c[tm].pos);
				swap(a[c[tm].pos],c[tm].v);
				add(c[tm].pos);
			}
			if(!(c[tm].pos>=ql&&c[tm].pos<=qr))swap(a[c[tm].pos],c[tm].v);
		}
		while(tm>qt){
			if(c[tm].pos>=ql&&c[tm].pos<=qr){
				del(c[tm].pos);
				swap(a[c[tm].pos],c[tm].v);
				add(c[tm].pos);
			}
			if(!(c[tm].pos>=ql&&c[tm].pos<=qr))swap(a[c[tm].pos],c[tm].v);
			--tm;
		}
		ans[q[i].id]=Get();
	}
	for(register int i=1;i<=cntq;++i)write(ans[i]),puts("");
	return 0;
}
posted @ 2020-05-23 12:10  Refined_heart  阅读(196)  评论(0编辑  收藏  举报