先考虑对于一个序列,能使其可以删空的的修改次数。

首先可以发现,序列的排列顺序是没有影响的,所以可以将所有数放到桶里来处理。

尝试对一个没有经过修改的可以删空的序列来进行删数,一开始删去所有的\(n\),然后序列长度变为\(x_1\),删去所有的\(x_1\),然后序列长度变为\(x_2\),删去所有的\(x_2\)……直到对于一个长度为\(x_i\)的序列,其中没有\(x_i\)这个数,那么此时就要对序列执行修改操作了。

考虑过程,当不能连续的删数时,就需要通过修改来填补空缺。实际上,对\([1,n]\)做前缀和,存在数字的位置需满足该位置的值等于该位置的下标,不然就需进行修改。

可以发现对于\([1,n]\)的每个出现的数字,从其往前覆盖一条长度为该数出现次数的线段,区间\([1,n]\)未被覆盖的位置个数即为需要修改的次数。

可以通过线段树来维护最小值的个数来统计未被覆盖的位置个数。

考虑加上修改操作,单点修改直接改修改前后两个数的贡献即可,整体加减可以对线段树的询问加上偏移量,比如当整体加一时,偏移量减一,询问的区间向左移动。

然后对于一些不在当前询问区间的数字的贡献需要忽略,我的处理是在询问区间右边的数字就不再计算贡献。

\(code:\)

#include<bits/stdc++.h>
#define maxn 2000010
#define all 450000
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,root=1,delta=150000;
int a[maxn],cnt[maxn],add[maxn];
struct node
{
int mi,cnt;
}t[maxn];
node operator +(const node &a,const node &b)
{
if(a.mi<b.mi) return a;
if(a.mi>b.mi) return b;
return (node){a.mi,a.cnt+b.cnt};
}
void pushadd(int cur,int v)
{
t[cur].mi+=v,add[cur]+=v;
}
void pushdown(int cur)
{
if(!add[cur]) return;
pushadd(ls,add[cur]),pushadd(rs,add[cur]),add[cur]=0;
}
void build(int l,int r,int cur)
{
if(l==r)
{
t[cur]=(node){0,1};
return;
}
build(l,mid,ls),build(mid+1,r,rs),t[cur]=t[ls]+t[rs];
}
void modify(int L,int R,int l,int r,int v,int cur)
{
if(L>R) return;
if(L<=l&&R>=r)
{
pushadd(cur,v);
return;
}
pushdown(cur);
if(L<=mid) modify(L,R,l,mid,v,ls);
if(R>mid) modify(L,R,mid+1,r,v,rs);
t[cur]=t[ls]+t[rs];
}
node query(int L,int R,int l,int r,int cur)
{
if(L<=l&&R>=r) return t[cur];
pushdown(cur);
if(R<=mid) return query(L,R,l,mid,ls);
if(L>mid) return query(L,R,mid+1,r,rs);
return query(L,R,l,mid,ls)+query(L,R,mid+1,r,rs);
}
int main()
{
read(n),read(m),build(1,all,root);
for(int i=1;i<=n;++i)
read(a[i]),a[i]+=delta,cnt[a[i]]++;
for(int i=1+delta;i<=n+delta;++i)
modify(i-cnt[i]+1,i,1,all,1,root);
while(m--)
{
int p,x;
read(p),read(x);
if(p)
{
if(a[p]<=n+delta) modify(a[p]-cnt[a[p]]+1,a[p]-cnt[a[p]]+1,1,all,-1,root);
cnt[a[p]]--,x+=delta,cnt[x]++,a[p]=x;
if(x<=n+delta) modify(x-cnt[x]+1,x-cnt[x]+1,1,all,1,root);
}
else
{
if(x==1) p=n+delta,modify(p-cnt[p]+1,p,1,all,-1,root),delta--;
else delta++,p=n+delta,modify(p-cnt[p]+1,p,1,all,1,root);
}
node q=query(1+delta,n+delta,1,all,root);
if(q.mi) puts("0");
else printf("%d\n",q.cnt);
}
return 0;
}

题解 洛谷 P5324 【[BJOI2019]删数】的更多相关文章

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

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

  2. 【洛谷p1106】删数问题

    (洛谷t2755暂时过不去了) 删数问题[传送门] 洛谷算法标签: emmmm……删数问题又牵扯到了字符串.因为毕竟高精度的数240位呢!要是输入一个整型,要码240行来求出每一位……怕是还没求出来就 ...

  3. 【洛谷P2426】删数

    删数 题目链接 一道裸的区间DP,f[l][r]表示剩下区间[l,r]时的最大价值 可以由f[1~l-1][r]和f[l][r+1~n]转移过来 详见代码: #include<algorithm ...

  4. 【洛谷P1323】删数问题

    删数问题 题目链接 首先找出最小的k个数:用堆每次取出最小的元素p,将p*2+1和p*4+5压入堆. 贪心求最大数:从前往后找第一个data[j+1]>data[j],删除data[j].(链表 ...

  5. luogu P5324 [BJOI2019]删数

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

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

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

  7. 洛谷P4587 [FJOI2016]神秘数(主席树)

    题面 洛谷 题解 考虑暴力,对于询问中的一段区间\([l,r]\),我们先将其中的数升序排序,假设当前可以表示出\([1,k]\)目前处理\(a_i\),假如\(a_i>k+1\),则答案就是\ ...

  8. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  9. DP,数论————洛谷P4317 花神的数论题(求1~n二进制中1的个数和)

    玄学代码(是洛谷题解里的一位dalao小粉兔写的) //数位DP(二进制)计算出f[i]为恰好有i个的方案数. //答案为∏(i^f[i]),快速幂解决. #include<bits/stdc+ ...

随机推荐

  1. Cannot instantiate the type Map

    今天在使用Map中犯了个低级错误,记录一下: 打算使用map为一个视频List观看记录的统计标识,key为vid,value默认为false,当该key已经统计,标识value为true,初始实例化M ...

  2. 图解leetcode5-10 | 和233酱一起刷leetcode系列(2)

    本周我们继续来看5道磨人的小妖精,图解leetcode6-10- 多说一句,leetcode10 杀死了233酱不少脑细胞... 另: 沉迷算法,无法自拔.快来加入我们吧! 别忘了233酱的一条龙服务 ...

  3. 黎活明8天快速掌握android视频教程--27_网络通信之通过GET和POST方式提交参数给web应用

    1该项目主要实现Android客户端以get的方式或者post的方式向java web服务器提交参数 Android客户端通过get方式或者post方式将参数提交给后台服务器,后台服务器对收到的参数进 ...

  4. Python3-paramiko模块-基于SSH的远程连接模块

    Python3中的paramiko模块,基于SSH用于连接远程服务器并执行相关操作 http://docs.paramiko.org/en/2.1/ SSHClient 用于连接远程服务器并执行基本命 ...

  5. c++数字转化为字符串、字符串转换为数字

    char ch[20]; int i =1; int j = 2; char *p = "34567"; 数字装换为字符串 sprintf(ch , "%d,%d&quo ...

  6. 【vue】---- ElementUI 实现上传Excel

    1.功能描述:vue 项目使用 el-upload 实现上传 Excel. 2.功能效果:在el-upload基础上做了样式整改. 3.功能实现: // el-upload 上传组件 <temp ...

  7. 使用phpQuery进行采集数据,模拟curl提升访问速度

    使用php采集网页数据一般有多种方法,有时候会使用正则去采集页面,但是当我们需要采集的页面大并且多的话,会严重的浪费我们的cpu,这时候我们可以使用phpQuer来进行采集,不知道phpQuery的童 ...

  8. debian10 安装 详解

    准备 下载debian 下载页面,有3个iso,选择第一个,其他两个软件包,我们不需要. 制作启动盘 debian官方提供了一个工具,可以轻松制作启动盘,也可以用opensuse官方提供的一个工具ru ...

  9. Netty 源码解析(五): Netty 的线程池分析

    今天是猿灯塔“365篇原创计划”第五篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...

  10. 解决移动端点击穿透问题_h5实现移动端点击事件穿透的多种解决方案

    移动端点透点透现象出现的场景: 当A/B两个层上下z轴重叠,上层的A点击后消失或移开(这一点很重要),并且B元素本身有默认click事件(如a标签)或绑定了click事件.在这种情况下,点击A/B重叠 ...