【题解】Codeforces-940F Machine Learning

Problem

cf太麻烦就用洛谷

题意:给定一个数组,维护两种操作:
1、查询一段区间内的所有数字出现次数的mex
2、修改某点的值

Solution

像这种有关出现次数的多组区间询问的题目,当然蒟蒻只会用莫队啦

很明显带修改莫队,用一个桶 t 1 [ x ] 维护 x 的出现次数,用另一个桶 t 2 [ x ] 维护所有数字中 t 1 [ i ] == x ,最后看 t 2 中第一个为空的即可

一开始想到动态维护 m e x ,用堆比较方便维护,但带修莫队的复杂度 O ( n 5 3 ) 10 5 的数据下显得苍白无力,本来就要卡卡常,无法带一个 l o g 2 n 一起嗨皮

想到如果想法把 m e x 设为最大,则该数列至少含 i = 1 m e x 1 i = m e x ( m e x 1 ) 2 个元素,由于序列长度在 10 5 的范围,则 m e x < 448

可以将 l o g 2 n 替换为 l o g 2 448 9

但这样还是不能带着这个常数一起嗨

发现如果每次询问时暴力扫描,就可以不用把这个常数带在莫队上

最后离散化即可

贴一个自己容易错的地方:在设置带修莫队块的大小时 2 3

//要写成
int block = pow(n,2.0/3);
//而不是
int block = pow(n,2/3);

Code

//CF-940F
#include<algorithm>
#include<cstdio>
#include<cctype>
#include<cmath>
using namespace std;
#define rg register

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=101000;
struct Change{int p,u,v;}c[N];
int tmp[N<<1],a[N],Ans[N],blk[N];
int t1[N<<1],t2[N<<1];
int n,Q,q_;
struct node{
    int l,r,id,t;
    inline bool operator < (const node&bb) const {
        if(blk[l]==blk[bb.l]&&blk[r]==blk[bb.r])return t<bb.t;
        if(blk[l]==blk[bb.l])return blk[r]<blk[bb.r];
        return blk[l]<blk[bb.l];
    }
}q[N];

int main(){
    read(n);read(Q);rg int now=(0);
    for(rg int i=1;i<=n;++i)tmp[++tmp[0]]=read(a[i]);
    for(rg int i=1,opt;i<=Q;++i){
        read(opt);
        if(opt==1){
            ++q_;read(q[q_].l);read(q[q_].r);
            q[q_].t=now;q[q_].id=q_;
        }else {
            ++now;read(c[now].p);
            tmp[++tmp[0]]=read(c[now].v);
        }
    }
    sort(tmp+1,tmp+tmp[0]+1);
    int tmplen=unique(tmp+1,tmp+tmp[0]+1)-tmp-1;
    for(rg int i=1;i<=n;++i)a[i]=lower_bound(tmp+1,tmp+tmplen+1,a[i])-tmp;
    for(rg int i=1;i<=now;++i)c[i].v=lower_bound(tmp+1,tmp+tmplen+1,c[i].v)-tmp;

    int block=pow(n,2.0/3);
    for(rg int i=1;i<=n;++i)blk[i]=(i-1)/block+1;
    sort(q+1,q+q_+1);

    for(rg int i=1;i<=now;++i){
        c[i].u=a[c[i].p];
        a[c[i].p]=c[i].v;
    }
    rg int l=1,r=0,t=now;
    for(rg int i=1;i<=q_;++i){
        while(t<q[i].t){
            ++t;
            if(l<=c[t].p&&c[t].p<=r){
                --t2[t1[c[t].u]],
                --t1[c[t].u],
                ++t2[t1[c[t].u]],

                --t2[t1[c[t].v]],
                ++t1[c[t].v],
                ++t2[t1[c[t].v]];
            }
            a[c[t].p]=c[t].v;
        }
        while(q[i].t<t){
            if(l<=c[t].p&&c[t].p<=r){
                --t2[t1[c[t].v]],
                --t1[c[t].v],
                ++t2[t1[c[t].v]],

                --t2[t1[c[t].u]],
                ++t1[c[t].u],
                ++t2[t1[c[t].u]];
            }
            a[c[t].p]=c[t].u,--t;
        }
        while(q[i].l<l){--l,--t2[t1[a[l]]],++t1[a[l]],++t2[t1[a[l]]];}
        while(r<q[i].r){++r,--t2[t1[a[r]]],++t1[a[r]],++t2[t1[a[r]]];}
        while(l<q[i].l){--t2[t1[a[l]]],--t1[a[l]],++t2[t1[a[l]]],++l;}
        while(q[i].r<r){--t2[t1[a[r]]],--t1[a[r]],++t2[t1[a[r]]],--r;}
        for(rg int j=1;;++j)if(!t2[j]){Ans[q[i].id]=j;break;}
    }
    for(rg int i=1;i<=q_;++i)printf("%d\n",Ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40515553/article/details/79903097