传送门

不如先考虑暴力,能删的序列首先有\(1,2,3...n\),还有就是升序排序后从后往前放数,第\(i\)位要么放\(i\),要么放\(i+1\)位置的数,例如\(1,2,4,4,5,6,9,9,9\)

如果一个数\(i\)出现了若干次,假如是\(num_i\)次,我们发现是可以在\(i,i-1,i-2...i-num_i+1\)上放\(i\)的,这样放完之后,如果有的位置没有用到现有的数放上去,那么就要从没用的数里改一个放过来,问题也就是用一堆数,最多能放多少个位置.考虑从后往前放,然后如果一个位置有多个数就接着用这种数往后放.如果放到一个位置\(j\),\(j\)有若干个,当前的\(i\)也有若干个,我们只能用一种放,那么显然要用更多的那种放.最后没放数的位置数就是答案.

为了方便,我们把放数看成区间覆盖,即一个\(i\)可以覆盖\([i-num_i+1,i]\)这段区间,我们再给所有覆盖区间加上\(1\),那就是求\([1,n]\)中\(0\)的个数.注意到修改的\(+1/-1\)都是整体的,所以如果把所有数放在一根数轴上,那么初始要统计的区间为\([1,n]\),然后整体\(+1\)相当于统计区间整体向左移\(1\),然后 以原统计区间右端点 为右端点 的对应区间覆盖的贡献要减掉,因为那个右端点的数超过统计范围,不能放进来;整体\(-1\)相当于统计区间整体向右移\(1\),然后 以原统计区间右端点 为右端点 的对应区间覆盖的贡献要加上;单点修改,也就是原来的\(num_{a_p}\)减\(1\),后面的新的\(num\)加\(1\),这导致对应两个覆盖区间左端点右移和左移.这些东西可以用线段树维护,注意线段树的叶子数量应该是\(n+q+q\)

至于区间\(0\)的数量,用值域线段树维护因为区间\(+1\),某个位置最少为\(0\),只要维护区间最小值及数量就行了

// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double using namespace std;
const int N=150000+10,M=N*3;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
struct node
{
int mi,nm;
node(){mi=0,nm=1;}
node(int nmi,int nnm){mi=nmi,nm=nnm;}
node operator + (const node &bb) const
{
if(mi==bb.mi) return node(mi,nm+bb.nm);
return mi<bb.mi?(*this):bb;
}
void ad(int x){mi+=x;}
}s[M<<2],nw;
int tg[M<<2];
void psup(int o){s[o]=s[o<<1]+s[o<<1|1];}
void psdn(int o){if(tg[o]) s[o<<1].ad(tg[o]),tg[o<<1]+=tg[o],s[o<<1|1].ad(tg[o]),tg[o<<1|1]+=tg[o],tg[o]=0;}
#define mid ((l+r)>>1)
int nl,nr;
void modif(int o,int l,int r,int ll,int rr,int x)
{
if(ll<=l&&r<=rr){s[o].ad(x),tg[o]+=x;return;}
psdn(o);
if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
psup(o);
}
void modif(int lx,int x)
{
int o=1,l=nl,r=nr,st[21],tp=0;
while(l<r)
{
st[++tp]=o,psdn(o);
if(lx<=mid) o=o<<1,r=mid;
else o=o<<1|1,l=mid+1;
}
s[o].ad(x);
while(tp)
{
o=st[tp--];
psup(o);
}
}
node quer(int o,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return s[o];
psdn(o);
node an;
an.mi=M;
if(ll<=mid) an=an+quer(o<<1,l,mid,ll,rr);
if(rr>mid) an=an+quer(o<<1|1,mid+1,r,ll,rr);
psup(o);
return an;
}
void bui(int o,int l,int r)
{
if(l==r) return;
bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
psup(o);
}
int n,q,a[N],nm[M],ll=150001,rr; int main()
{
n=rd(),q=rd();
rr=ll+n-1;
nl=ll-q,nr=rr+q;
bui(1,nl,nr);
for(int i=1;i<=n;++i)
{
a[i]=rd()+ll-1;
++nm[a[i]];
modif(a[i]-nm[a[i]]+1,1);
}
while(q--)
{
int p=rd();
if(!p)
{
if(~rd())
{
if(nm[rr]) modif(1,nl,nr,rr-nm[rr]+1,rr,-1);
--ll,--rr;
}
else
{
++ll,++rr;
if(nm[rr]) modif(1,nl,nr,rr-nm[rr]+1,rr,1);
}
}
else
{
if(a[p]<=rr) modif(a[p]-nm[a[p]]+1,-1);
--nm[a[p]];
a[p]=rd()+ll-1;
++nm[a[p]];
modif(a[p]-nm[a[p]]+1,1);
}
nw=quer(1,nl,nr,ll,rr);
printf("%d\n",nw.mi?0:nw.nm);
}
return 0;
}

luogu P5324 [BJOI2019]删数的更多相关文章

  1. 【题解】Luogu P5324 [BJOI2019]删数

    原题传送门 易知这个数列的顺序是不用考虑的 我们看两个数列 \(1,2,3\)和\(3,3,3\)都能删完,再看两个数列\(1,2,3,4\)和\(2,2,4,4\),也都能删完 不难发现,我们珂以把 ...

  2. [BJOI2019]删数(线段树)

    [BJOI2019]删数(线段树) 题面 洛谷 题解 按照值域我们把每个数的出现次数画成一根根的柱子,然后把柱子向左推导,\([1,n]\)中未被覆盖的区间长度就是答案. 于是问题变成了单点修改值,即 ...

  3. 题解 洛谷 P5324 【[BJOI2019]删数】

    先考虑对于一个序列,能使其可以删空的的修改次数. 首先可以发现,序列的排列顺序是没有影响的,所以可以将所有数放到桶里来处理. 尝试对一个没有经过修改的可以删空的序列来进行删数,一开始删去所有的\(n\ ...

  4. [BJOI2019] 删数

    https://www.luogu.org/problemnew/show/P5324 题解 首先我们需要弄清这个答案是什么. 对于一个长度为n的序列,那么它先删的肯定是\(n\),删完之后它就会跳到 ...

  5. [BJOI2019] 删数 [dp转贪心结论+线段树]

    题面 传送门 思路 dp部分 以下称合法序列为原题面中可以删空的序列 这个是我在模拟考场上的思路 一开始我是觉得,这个首先可以写成一个dp的形式:$dp[i][j]$表示用$j$个数字填满了目标序列的 ...

  6. Luogu P2426 【删数】

    状态定义: 一眼区间$DP$,从左右两边删不好定义状态,不如定义$dp[i][j]$表示$[i,j]$未删的最大值,转移就很自然了 转移: 从左边删$dp[i][j]=max(dp[i][j],dp[ ...

  7. Luogu5324 BJOI2019删数(线段树)

    考虑无修改怎么做.对于1~n的每个数,若其存在,将最后一个放在其值的位置,剩余在其前面依次排列,答案即为值域1~n上没有数的位置个数.带修改显然记一下偏移量线段树改一改就好了. #include< ...

  8. [Luogu5324][BJOI2019]删数(线段树)

    CF风格题,先猜结论,记数列中i这个数共出现了cnt[i]次,那么所有区间[i-cnt[i]+1,i]的并集的补集大小就是答案. 于是我们只需要线段树维护每个位置是否被某个区间覆盖到即可,对于整体加减 ...

  9. 【LOJ】#3094. 「BJOI2019」删数

    LOJ#3094. 「BJOI2019」删数 之前做atcoder做到过这个结论结果我忘了... em,就是\([1,n]\)之间每个数\(i\),然后\([i - cnt[i] + 1,i]\)可以 ...

随机推荐

  1. selenium之元素定位-css

    CSS定位方式和XPATH定位方式基本相同,只是CSS定位表达式有其自己的格式.CSS定位方式拥有比XPATH定位速度快,且比XPATH稳定的特性.下面详细介绍CSS定位方式的使用方法 被测网页的HT ...

  2. ​Installing the Ranger Kafka Plug-in

    This section describes how to install and enable the Ranger Kafka plug-in. The Ranger Kafka plug-in ...

  3. dicom错误解决

    https://github.com/pydicom/pydicom/issues/331 sudo apt-get install python-gdcm

  4. Linux:Day20(上) openssh和CA

    ssh:secure shell protocol,22/tcp,安全的远程登陆 OpenSSH:ssh协议的开源实现: dripbear:另一个开源实现: SSH协议版本 v1:基于CRC-32做M ...

  5. oracle 行列转换

    oracle 行列转换列名如果是数字,用双引号包住  如下: --  建表 create table workinfo(wid integer primary key,sid integer ,CON ...

  6. MySQL数据库聚合函数

    +++++++++++++++++++++++++++++++++++++++++++标题:MySQL数据库聚合函数时间:2019年2月25日内容:MySQL数据库聚合函数重点:MySQL数据库聚合函 ...

  7. Django(三) ORM 数据库操作

    大纲 一.DjangoORM 创建基本类型及生成数据库表结构 1.简介 2.创建数据库 表结构 二.Django ORM基本增删改查 1.表数据增删改查 2.表结构修改 三.Django ORM 字段 ...

  8. c提高第四课

    1.一维数组的初始化 , , }; //3个元素 ] = { , , }; //a[3], a[4]自动初始化为0 ] = { }; //全部元素初始化为0 memset(c, , sizeof(c) ...

  9. React笔记:组件(3)

    1. 组件定义 组件是React的核心概念,组件将应用的UI拆分成独立的.可复用的模块. 定义组件的两种方式: (1)类组件:使用ES6 class (2)函数组件:使用函数 使用class定义组件的 ...

  10. Appium环境搭建-精简版

    Appium自动化环境准备 安装配置JDK 下载Android SDK并配置环境变量 安装模拟器或连接真机 安装appium desktop 安装python和pycharm (开发语言和开发工具) ...