https://www.luogu.org/problemnew/show/P5324

题解

首先我们需要弄清这个答案是什么。

对于一个长度为n的序列,那么它先删的肯定是\(n\),删完之后它就会跳到\(n-cnt[n]\)位置,然后变成子问题继续做 。

于是我们把每个数看做一条覆盖\(n-cnt[n]+1 \sim n\)的一条线段,那么有解的前提是\(1\sim n\)中的每个数都被覆盖了。

如果没有,需要调整多少次呢?

可以发现,我们可以花费一的代价将一条线段的长度-1,再将另一条线段长度+1,可以发现答案就是所有没有被覆盖的位置的长度和。

然后用线段树完成这个操作,整体加的话就将询问区间平移,注意:右端点不在询问区间内的线段要清掉。

代码

#include<bits/stdc++.h>
#define N 150009
#define P pair<int,int>
#define mm make_pair
using namespace std;
typedef long long ll;
int tr[N*12],la[N*12],num[N*12],nowl,nowr,maxn,n,m,a[N],tag;
map<int,int>tong;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
void build(int cnt,int l,int r){
num[cnt]=r-l+1;
if(l==r)return;
int mid=(l+r)>>1;
build(cnt<<1,l,mid);build(cnt<<1|1,mid+1,r);
}
inline void pushdown(int cnt){
la[cnt<<1]+=la[cnt];
tr[cnt<<1]+=la[cnt];
la[cnt<<1|1]+=la[cnt];
tr[cnt<<1|1]+=la[cnt];
la[cnt]=0;
}
inline P merge(P x,P y){
P z=x;
if(y.first<z.first)z=y;
else if(y.first==z.first)z.second+=y.second;
return z;
}
inline void pushup(int cnt){
tr[cnt]=tr[cnt<<1];num[cnt]=num[cnt<<1];
if(tr[cnt<<1|1]<tr[cnt])tr[cnt]=tr[cnt<<1|1],num[cnt]=num[cnt<<1|1];
else if(tr[cnt<<1|1]==tr[cnt])num[cnt]+=num[cnt<<1|1];
}
P query(int cnt,int l,int r,int L,int R){
if(l>=L&&r<=R)return mm(tr[cnt],num[cnt]);
int mid=(l+r)>>1;
if(la[cnt])pushdown(cnt);
if(mid>=L&&mid<R)return merge(query(cnt<<1,l,mid,L,R),query(cnt<<1|1,mid+1,r,L,R));
if(mid>=L)return query(cnt<<1,l,mid,L,R);
if(mid<R)return query(cnt<<1|1,mid+1,r,L,R);
}
void upd(int cnt,int l,int r,int L,int R,int tag){
if(l>=L&&r<=R){
tr[cnt]+=tag;
la[cnt]+=tag;
return;
}
int mid=(l+r)>>1;
if(la[cnt])pushdown(cnt);
if(mid>=L)upd(cnt<<1,l,mid,L,R,tag);
if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,tag);
pushup(cnt);
}
inline void work(int l,int r,int tag){
l=max(l,nowl);r=min(r,nowr);
if(l>r)return;
upd(1,1,maxn,l-nowl,r-nowl,tag);
}
int main(){
n=rd();m=rd();
nowl=1-m-1;nowr=n+m+1;
maxn=nowr-nowl+1;
build(1,1,maxn);
int ls=1,rs=n;
for(int i=1;i<=n;++i)a[i]=rd(),tong[a[i]]++;
for(int i=1;i<=n;++i)work(i-tong[i]+1,i,1);
int p,x;
while(m--){
p=rd();x=rd();
if(!p){
ls-=x;rs-=x;tag-=x;
if(x<0){
int xx=rs,yy=ls-1;
if(tong.find(xx)!=tong.end())work(xx-tong[xx]+1,xx,1);
if(tong.find(yy)!=tong.end())work(yy-tong[yy]+1,yy,-1);
}
else{
int xx=ls,yy=rs+1;
if(tong.find(xx)!=tong.end())work(xx-tong[xx]+1,xx,1);
if(tong.find(yy)!=tong.end())work(yy-tong[yy]+1,yy,-1);
}
}
else{
x+=tag;
if(a[p]>=ls&&a[p]<=rs)work(a[p]-tong[a[p]]+1,a[p]-tong[a[p]]+1,-1);
tong[a[p]]--;
a[p]=x;
tong[a[p]]++;
if(a[p]>=ls&&a[p]<=rs)work(a[p]-tong[a[p]]+1,a[p]-tong[a[p]]+1,1);
}
P xx=query(1,1,maxn,ls-nowl,rs-nowl);
if(xx.first==0)printf("%d\n",xx.second);
else puts("0");
}
return 0;
}

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

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

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

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

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

  3. luogu P5324 [BJOI2019]删数

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

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

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

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

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

  6. Luogu5324 BJOI2019删数(线段树)

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

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

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

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

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

  9. codevs4096 删数问题

    题目描述 Description 键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数.编程对给定的N 和S,寻找一种方案使得剩下的数字组成的新数最小. 输入 ...

随机推荐

  1. [MySQL] mysql的逻辑分层

    mysql逻辑分层:1.client ==>连接层 ==>服务层==>引擎层==>存储层 server2.连接层: 提供与客户端连接的服务3.服务层: 1.提供各种用户使用的接 ...

  2. headfirst设计模式(6)—单例模式

    前言 这一章的课题看起来就很和蔼可亲了,比起前面绕的我不要不要的工厂模式,那感觉真是太好了,但是正是因为简单,那么问题就来了,我怎么才能把这个东西叙述清楚?怎么样才能老少咸宜呢? 如何能够在把这个东西 ...

  3. Python二级-----------程序冲刺2

    1. 编写 Python 程序输出一个具有如下风格效果的文本,用作文本进度条样式,部分代码如下,填写空格处.‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬ ...

  4. pthread小结

    参考1 https://computing.llnl.gov/tutorials/pthreads/ 参考2 http://man7.org/linux/man-pages/man7/pthreads ...

  5. Android Interpolator解析

    本文部分图片转自:https://blog.csdn.net/lgaojiantong/article/details/39451243 目录 自定义插值器 系统插值器 1. 自定义插值器 要自定义插 ...

  6. 小米平板8.0以上系统如何不用root激活xposed框架的流程

    在大多使用室的引流,或业务操作中,基本上都需要使用安卓的强大XPOSED框架,近来我们使用室购来了一批新的小米平板8.0以上系统,基本上都都是基于7.0以上系统版本,基本上都不能够刷入ROOT的su权 ...

  7. Android Studio教程05-Parcelables和Bundles.md

    Parcelable并且Bundle对象旨在用于跨IPC / Binder事务等进程边界,活动与意图之间以及跨配置更改存储瞬态.本页面提供使用Parcelable和Bundle对象的建议和最佳实践 . ...

  8. 【English】十四、英语

    一.英语 是 词法(词) + 语法 一个个拥有词法的词,就是材料.通过语法的规则将这些词合理组合排列起来.然后,就可以干很多事了.

  9. Jenkins实现简单的CI功能

    步骤一:安装JDK.Tomcat,小儿科的东西不在此详细描述 步骤二:下载安装Jenkins下载链接:https://jenkins.io/download/ 步骤三:将下载的jenkins.war部 ...

  10. Cannot connect to WMI Provider & Invalid class [0x80041010]

    数据库服务器(Virtual Machine)所在的Nutanix一台主机由于故障,VM自动切换到另一台主机,切换过程中VM会重新启动,但是早上检查的时候,发现点击SQL Server Configu ...