CF940F Machine Learning(带修莫队)

首先显然应该把数组离散化,然后发现是个带修莫队裸题,但是求mex比较讨厌,怎么办?其实可以这样求:记录每个数出现的次数,以及出现次数的出现次数。至于求mex,直接暴力扫最小的出现次数的出现次数为0的正整数,就一句话,这样看似会超时,实际上是O(√n)的复杂度。为什么?假设存在出现1,2,...,x的出现次数,则Σi(1<=i<=x)<=n,即x*(x+1)<=2*n,所以x至多是√n级别。很多人再把出现次数分块,根本没必要。然后考虑把数组分块的块大小,每次移动左指针,为O(n*块大小),移动右指针,为O(n*块大小+n*块个数),移动修改标记,为O(n*块个数2),然后显然块大小为O(n2/3)最优,复杂度O(n5/3)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
struct query{int l,r,t,id;}q[N];
struct mdf{int pos,pre,now;}d[N];
int n,m,B,l=1,r,cnt,qcnt,mcnt,a[N],b[N],c[N],tmp[N],tot[N],num[N],ans[N];
bool cmp(query a,query b)
{
    if((a.l-1)/B!=(b.l-1)/B)return a.l<b.l;
    return(a.r-1)/B==(b.r-1)/B?a.t<b.t:a.r<b.r;
}
void add(int x,int v){tot[num[x]]--,num[x]+=v,tot[num[x]]++;}
void modify(int i,int f)
{
    if(d[i].pos>=l&&d[i].pos<=r)add(a[d[i].pos],-1);
    a[d[i].pos]=f==1?d[i].now:d[i].pre;
    if(d[i].pos>=l&&d[i].pos<=r)add(a[d[i].pos],1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),tmp[++cnt]=a[i];
    for(int i=1;i<=m;i++)
    {
        int op,x,y;scanf("%d%d%d",&op,&x,&y);
        if(op==1)q[++qcnt]=(query){x,y,mcnt,qcnt};
        else d[++mcnt]=(mdf){x,0,y},tmp[++cnt]=y;
    }
    sort(tmp+1,tmp+cnt+1);
    cnt=unique(tmp+1,tmp+cnt+1)-tmp-1;
    for(int i=1;i<=n;i++)a[i]=b[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
    for(int i=1;i<=mcnt;i++)
    {
        d[i].now=lower_bound(tmp+1,tmp+cnt+1,d[i].now)-tmp;
        d[i].pre=b[d[i].pos],b[d[i].pos]=d[i].now;
    }
    B=pow(n,0.67);
    sort(q+1,q+qcnt+1,cmp);
    for(int i=1,tm=0;i<=qcnt;i++)
    {
        while(tm<q[i].t)modify(++tm,1);
        while(tm>q[i].t)modify(tm--,-1);
        while(r<q[i].r)add(a[++r],1);
        while(l>q[i].l)add(a[--l],1);
        while(r>q[i].r)add(a[r--],-1);
        while(l<q[i].l)add(a[l++],-1);
        ans[q[i].id]=1;
        while(tot[ans[q[i].id]])ans[q[i].id]++;
    }
    for(int i=1;i<=qcnt;i++)printf("%d\n",ans[i]);
}

原文地址:https://www.cnblogs.com/hfctf0210/p/11179323.html

时间: 2024-08-29 20:19:10

CF940F Machine Learning(带修莫队)的相关文章

CF940F Machine Learning (带修改莫队)

题目链接 https://codeforces.com/contest/940/problem/F 题意 给出n个数字,q个询问: 每次询问有两种类型,一种是询问区间,一种是单体修改: 定义Ci为区间里数字 i 出现的次数,求Ci数组的mex #include<bits/stdc++.h> using namespace std; const int maxx = 2e5+10; struct qnode { int l,r,t,id; }e[maxx]; struct cnode { int

【BZOJ-3052】糖果公园 树上带修莫队算法

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 883  Solved: 419[Submit][Status][Discuss] Description Input Output Sample Input Sample Output 84 131 27 84 HINT Source Solution 树上带修莫队 本质还是树上莫队,详情可以转 BZOJ-3757苹果树 但是这里需要修改,就需要一些特殊的地方

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &

2120: 数颜色(带修莫队)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2120 2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 10514  Solved: 4398[Submit][Status][Discuss] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R

莫队 + 带修莫队

莫队其实就是一个带优化的暴力,通过将区间询问按一定规则进行排序,从而优化过程,求出答案. 举一例子:(例子不具备权威性,只是让读者了解莫队是干啥的) /* 输入四个区间 1 4 初始条件,L= R = 0, 将R遍历到4 需要走4步 L走一步,共5次 4 8 继承上一次 L 和 R 的值,L从1到4 需要3次,R从4到8,需4次, 总计8次 2 9 同理继承, L回退2次, R前进一次 总计3次 1 2 同理,L回退1次,R回退7次 总计8次 如果直接暴力,计算机将要计算 5+8+3+8=24次

bzoj4129 Haruna’s Breakfast 树上带修莫队+分块

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4129 题解 考虑没有修改的序列上的版本应该怎么做: 弱化的题目应该是这样的: 给定一个序列,每次询问区间 \([l, r]\) 中元素的最小没有出现的自然数. 这个弱化的版本可以用离线+线段树二分水掉.但是这个做法显然不太好搬到树上做. 上面的弱化版还有一个莫队做法:可以用莫队维护出来每一个区间的每一个数的出现为次数.把出现过的数通过分块表示出来,于是查询的时候枚举每一个块,寻找第一个不满的

数颜色(带修莫队模板)

数颜色(luogu) Description 题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 为了满足墨墨的要求,你知道你需要干什么了吗? 输入格式 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数. 第2行N个整数,分别代表初始画笔排中第i支画笔的颜色. 第3行到第2+M行

F. Machine Learning 带修端点莫队

F. Machine Learning time limit per test 4 seconds memory limit per test 512 megabytes input standard input output standard output You come home and fell some unpleasant smell. Where is it coming from? You are given an array a. You have to answer the

BZOJ4129(树上带修莫队)

树上莫队的基本思路是把树按dfs序分块,然后先按x所在块从小到大排序,再按y所在块从小到大排序,处理询问即可. 这道题带修改,再加一个时间维即可. 时间复杂度据说是$n^{\frac53}$,不知道是为什么. (块大小改成3也过了什么鬼..) #include <cstdio> #include <algorithm> using namespace std; const int N=50005,M=100005,B=1357,T=223; int n,m,e,x,y,t,tp,o