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. jQuery(八)、ajax

    1.jQuery.ajax(url[, settings]) 通过HTTP请求加载远程数据. 注意:所有的settings选择都可以通过$.ajaxSetup()函数来全局指定. 回调函数 在实际开发 ...

  2. oracle学习笔记(三) DCL 数据控制语言与 DDL 数据定义语言

    DCL 数据控制语言 Data control language 之前说过的授权和收权利语句 grant, revoke DDL 数据定义语言 Data define language create ...

  3. Spring Cloud 微服务开发系列整理

    Spring Boot 系列精选 Spring Boot 自定义 starter Spring Boot 整合 mybatis-plus Spring Boot 整合 spring cache Spr ...

  4. asp.net Core HttpClient 出现Cannot access a disposed object. Object name: 'SocketsHttpHandler' 的问题。

    ASP.NET Core 部署在Centos 中 偶尔出现 One or more errors occurred. (Cannot access a disposed object.Object n ...

  5. webpack使用exclude

    在进行项目打包的时候,当使用babel-loader进行js兼容时,不需要将node_modules模块下的所有js文件进行打包.

  6. linux添加crontab定时任务

    1.crontab -e命令进入linux定时任务编辑界面,举个简单的例子,比如我要定时往txt文件写入 */ * * * * .txt */1就是每隔一分钟像文件写入,其他一些详细的操作大家可以去网 ...

  7. Hive动态分区

    1.开启支持动态分区 set hive.exec.dynamic.partition=true; --默认为false set hive.exec.dynamic.partition.mode=nos ...

  8. 简单的C#实体映射 AutoMapper

    AutoMapper是对象到对象的映射工具.在完成映射规则之后,AutoMapper可以将源对象转换为目标对象. 要映射实体 public class SourceModel { public int ...

  9. 使用make

    5.11 库的使用 代码的复用是计算机程序设计语言中的一个重要的概念.可以把编译好的目标文件模块统一放到一个库中,使得程序员可以在不同的程序中共享这些代码. 在Linux操作系统下,最后连接生成可执行 ...

  10. 定义工作,解读自我——IT帮2019年2月线下活动回顾

    本次活动是在北京和深圳两个分站同步进行的,IT团建委员会负责策划和组织,北京站由帮主周老师.王兵老师主导,深圳站由副帮主兼深圳站长陈焕老师主导. 几位老师都是有着丰富的工作经历和人生体验的导师,他们不 ...