• 【题解】CF940F Machine Learning


    Link

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

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

    ( ext{Solution:})

    这是带修莫队的一道题。

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

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

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

    下面是一些处理技巧:

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

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

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

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

    那么:

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

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

    (1e5)的情况下这个复杂度还是可以的。在( ext{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;
    }
    
  • 相关阅读:
    设计模式
    显示WiFi密码
    05-变量
    04-杂谈
    03-杂谈
    02-杂谈
    01-linux介绍、命令
    14-python--inner
    13-python--bibao
    11-python-iterator
  • 原文地址:https://www.cnblogs.com/h-lka/p/12941934.html
Copyright © 2020-2023  润新知