题目大意:一个数列若能在有限次数内删空,则称这个数列可以删空,一次删除操作定义如下:

记当前数列长度为$k$,则删掉数列中所有等于$k$的数。

现在有一个长度为$n$的数列$a$,有$m$次修改操作,为单点变值/整体增加或者减少$1$,问每次修改后,最少需要修改序列中多少个数,使得序列可以被删除。

数据范围:$n≤150000$。

我们首先考虑下最少需要修改的次数,我们设$b[i]$为数列$a$中填写了i的值得数量。

对于每一个$i$,我们可以用$b[i]$这么多数,覆盖区间$[i-b[i]+1,i]$。最终的答案就是未被覆盖的格子数量。

证明显然。

基于这个结论,我们就可以在$O(n)$的复杂度内求出一个序列$a$对应的答案,可以获得47分的好成绩。

在只有单点修改的情况下,我们发现我们可以用线段树做一下维护,就可以获得60分的好成绩。

我们发现,整体的$+1$或者$-1$,可以转化为查询的区间出现了移动,移动完查询区间后,我们更新一下两端的值即可。

这么搞就可以过掉这一题了。

时间复杂度:$O(n\log\ n)$。

 #include<bits/stdc++.h>
#define M (1<<19)
using namespace std; struct seg{int l,r,tag,minn,cnt;}a[M<<];
void pushup(int x){
a[x].minn=min(a[x<<].minn,a[x<<|].minn);
a[x].cnt=(a[x].minn==a[x<<].minn?a[x<<].cnt:)+(a[x].minn==a[x<<|].minn?a[x<<|].cnt:);
}
void upd(int x,int k){a[x].minn+=k; a[x].tag+=k;}
void pushdown(int x){if(a[x].tag) upd(x<<,a[x].tag),upd(x<<|,a[x].tag); a[x].tag=;} void build(int x,int l,int r){
a[x].l=l; a[x].r=r; if(l==r) return void(a[x].cnt=);
int mid=(l+r)>>;
build(x<<,l,mid); build(x<<|,mid+,r);
pushup(x);
}
void updata(int x,int l,int r,int k){
if(l<=a[x].l&&a[x].r<=r) return upd(x,k);
pushdown(x); int mid=(a[x].l+a[x].r)>>;
if(l<=mid) updata(x<<,l,r,k);
if(mid<r) updata(x<<|,l,r,k);
pushup(x);
}
void updata(int x,int id,int k){return updata(x,id,id,k);}
int query(int x,int l,int r){
if(a[x].minn>) return ;
if(l<=a[x].l&&a[x].r<=r) return a[x].cnt;
pushdown(x); int mid=(a[x].l+a[x].r)>>,cnt=;
if(l<=mid) cnt+=query(x<<,l,r);
if(mid<r) cnt+=query(x<<|,l,r);
return cnt;
} int num[M],n,q,m,orzorz[M*]={};
int *cnt=orzorz+M;
int main(){
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++) scanf("%d",num+i),cnt[num[i]]++;
int T=max(n,q),m=T+n+q+,move=;
build(,,m);
for(int i=;i<=n;i++) updata(,T+i-cnt[i]+,T+i,);
while(q--){
int p,x; scanf("%d%d",&p,&x);
if(p>){
x-=move;
if(num[p]+move>=&&num[p]+move<=n)
updata(,num[p]-cnt[num[p]]++T,-);
cnt[num[p]]--; num[p]=x; cnt[num[p]]++;
updata(,num[p]-cnt[num[p]]++T,);
}else{
if(x<) move--;
updata(,-move-cnt[-move]++T,-move+T,x);
updata(,n-move-cnt[n-move]++T,n-move+T,-x);
if(x>) move++;
}
printf("%d\n",query(,T-move+,T-move+n));
}
}

【BJOI2019】删数 线段树的更多相关文章

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

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

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

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

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

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

  4. Luogu5324 BJOI2019删数(线段树)

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

  5. luogu P5324 [BJOI2019]删数

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

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

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

  7. Problem 1007 幸运数 线段树成段更新

    题目链接: 题目 Problem 1007 幸运数 Time Limit: 2000 mSec Memory Limit : 131072 KB 问题描述 皮特的幸运数是2和5.只由幸运数字2和5组成 ...

  8. [BJOI2019] 删数

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

  9. hdu 4417 区间内比h小的数 线段树

    题意求区间内比h小的数的个数 将所有的询问离线读入之后,按H从小到大排序.然后对于所有的结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,然后就是一个区间和. 2015-07-27:专 ...

随机推荐

  1. hive的常用操作

    1.hive的数据类型 tinyint/smallint/int/bigint tinyint:从 0 到 255 的整型数据 smallint:从 0 到 65535 的整型数据 int:从 0 到 ...

  2. oracle数据库分页总结

    /* BEGIN CREATE TABLE APPUSER(IDS NUMBER(8), USERNAME VARCHAR2(20), PASSWORD VARCHAR2(20), CTIME DAT ...

  3. Python local error

    原来在python的函数中和全局同名的变量,如果你有修改变量的值就会变成局部变量,在修改之前对该变量的引用自然就会出现没定义这样的错误了,如果确定要引用全局变量,并且要对它修改,必须加上global关 ...

  4. 738. Monotone Increasing Digits 单调递增的最接近数字

    [抄题]: Given a non-negative integer N, find the largest number that is less than or equal to N with m ...

  5. map与forEach区别

    1.  forEach()返回的是undefined 不可以链式调用 return没有用 2. map()返回一个新数组 原数组不会改 3. 没办法终止或者跳过forEach()和map循环  除非抛 ...

  6. Solidity的地址 数组如何判断是否包含一个给定的地址?

    Q: given address[] wallets. What is the correct method to check that the list contains a given addre ...

  7. ORM初识和数据库操作

    ORM简介 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.简单的说,ORM是通过使用描述对象和数据库之 ...

  8. 20172306 2018-2019 《Java程序设计与数据结构》第一周学习总结

    20172306 2018-2019 <Java程序设计与数据结构(下)>第一周学习总结 教材学习内容总结 第一章 概述 (程序=数据结构+算法 软件=程序+软件工程) 1.1 软件质量 ...

  9. SQLite 安装

    Windows 平台安装 下载地址:https://www.sqlite.org/download.html 下载预编译的安装包 将下载的安装包=解压到一个文件夹,有三个重要文件: sqlite3.e ...

  10. Flink官方文档/介绍/教程/用例

    https://flink.apache.org/ 使用谷歌浏览器进入官网后,点击页面右键,使用谷歌翻译,翻译准确率很高: 常用部分: