[Codeforces940F][莫队算法]Machine Learning

翻译:

给出一个长度为n(n<=100000)的序列,序列中每个数a[i]<=10^9 设c[i]表示第i种数出现的次数
q(q<=100000)次询问,询问共有两种 第一种 1 x y 表示求序列中x~y
c[i]的mex。mex表示最小的没有出现过的值(不包括0) 第二种 2 x y 表示把序列中第x位的数替换为y

题解

治数据结构学傻系列这是万能的莫队
首先有一个性质,我们可以观察出结果一定不会大于1000,所以处理答案的时候暴力枚举就好。为什么?如果每个数恰好出现要求的次数,那么1加到1000也是超过100000的了,所以答案不会超过1000
于是用一个带修改的莫队水一下就OK了
排序打错TLE难受
复习了一发带修莫队以及莫队2333

/*
翻译: 
给出一个长度为n(n<=100000)的序列,序列中每个数a[i]<=10^9
设c[i]表示第i种数出现的次数 
q(q<=100000)次询问,询问共有两种
第一种 1 x y 表示求序列中x~y c[i]的mex。mex表示最小的没有出现过的值(不包括0) 
第二种 2 x y 表示把序列中第x位的数替换为y 
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
map<int,int> q;
int val[210000],len;
int l,r,t;
struct pck{int p,c,las;}ch[210000];int chlen;
struct ask
{
    int l,r,t,op;
}A[210000];int n,m,alen;
int block,pos[210000];
bool cmp(ask n1,ask n2)
{
    if(pos[n1.l]!=pos[n2.l])return pos[n1.l]<pos[n2.l];
    if(pos[n1.r]!=pos[n2.r])return pos[n1.r]<pos[n2.r];
    return n1.t<n2.t;
}
int vis[210000];//sum[i]的出现次数 
int col[210000],las[210000],answer[210000],ans;//las[i]表示第i个位置上一次的颜色 
int sum[210000];//每种数出现了多少次 
void upd_col(int now,int c)
{
    if(now>=l && now<=r)vis[sum[col[now]]]--,sum[col[now]]--,vis[sum[col[now]]]++;
    col[now]=c;
    if(now>=l && now<=r)vis[sum[col[now]]]--,sum[col[now]]++,vis[sum[col[now]]]++;
}
void del(int now)
{
    vis[sum[col[now]]]--;
    sum[col[now]]--;
    vis[sum[col[now]]]++;
}
void add(int now)
{
    vis[sum[col[now]]]--;
    sum[col[now]]++;
    vis[sum[col[now]]]++;
}
int gtans(){for(int i=1;;i++)if(vis[i]==0)return i;}
int main()
{
    scanf("%d%d",&n,&m);
    block=ceil(pow(n,2.0/3));
    for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&col[i]);
        val[++len]=col[i];las[i]=col[i];
    }
    for(int i=1;i<=m;i++)
    {
        int op,u,v;
        scanf("%d%d%d",&op,&u,&v);
        if(op==1)
        {
            alen++;
            A[alen].l=u;A[alen].r=v;A[alen].t=chlen;
            A[alen].op=i-chlen;
        }
        else
        {
            chlen++;ch[chlen].p=u;ch[chlen].c=v;
            ch[chlen].las=las[u];las[u]=v;
            val[++len]=v;
        }
    }
    sort(val+1,val+1+len);
    len=unique(val+1,val+1+len)-val-1;
    for(int i=1;i<=len;i++)q[val[i]]=i;
    for(int i=1;i<=chlen;i++)ch[i].las=q[ch[i].las],ch[i].c=q[ch[i].c];
    for(int i=1;i<=n;i++)col[i]=q[col[i]];
    sort(A+1,A+1+alen,cmp);
    l=A[1].l,r=A[1].r,t=A[1].t;
    for(int i=1;i<=A[1].t;i++)col[ch[i].p]=ch[i].c;
    for(int i=A[1].l;i<=A[1].r;i++)
    {
        vis[sum[col[i]]]--;
        sum[col[i]]++;
        vis[sum[col[i]]]++;
    }
    for(int i=1;;i++)if(vis[i]==0){answer[A[1].op]=i;break;}
    for(int i=2;i<=alen;i++)
    {
        while(t<A[i].t)t++,upd_col(ch[t].p,ch[t].c);
        while(t>A[i].t)upd_col(ch[t].p,ch[t].las),t--;
        while(l<A[i].l)del(l++);
        while(l>A[i].l)add(--l);
        while(r<A[i].r)add(++r);
        while(r>A[i].r)del(r--);
        answer[A[i].op]=gtans();
        //for(int j=l;j<=r;j++)printf("%d ",col[j]);
    }
    for(int i=1;i<=alen;i++)printf("%d\n",answer[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值