luogu P5324 [BJOI2019]删数
不如先考虑暴力,能删的序列首先有\(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]删数的更多相关文章
- 【题解】Luogu P5324 [BJOI2019]删数
原题传送门 易知这个数列的顺序是不用考虑的 我们看两个数列 \(1,2,3\)和\(3,3,3\)都能删完,再看两个数列\(1,2,3,4\)和\(2,2,4,4\),也都能删完 不难发现,我们珂以把 ...
- [BJOI2019]删数(线段树)
[BJOI2019]删数(线段树) 题面 洛谷 题解 按照值域我们把每个数的出现次数画成一根根的柱子,然后把柱子向左推导,\([1,n]\)中未被覆盖的区间长度就是答案. 于是问题变成了单点修改值,即 ...
- 题解 洛谷 P5324 【[BJOI2019]删数】
先考虑对于一个序列,能使其可以删空的的修改次数. 首先可以发现,序列的排列顺序是没有影响的,所以可以将所有数放到桶里来处理. 尝试对一个没有经过修改的可以删空的序列来进行删数,一开始删去所有的\(n\ ...
- [BJOI2019] 删数
https://www.luogu.org/problemnew/show/P5324 题解 首先我们需要弄清这个答案是什么. 对于一个长度为n的序列,那么它先删的肯定是\(n\),删完之后它就会跳到 ...
- [BJOI2019] 删数 [dp转贪心结论+线段树]
题面 传送门 思路 dp部分 以下称合法序列为原题面中可以删空的序列 这个是我在模拟考场上的思路 一开始我是觉得,这个首先可以写成一个dp的形式:$dp[i][j]$表示用$j$个数字填满了目标序列的 ...
- Luogu P2426 【删数】
状态定义: 一眼区间$DP$,从左右两边删不好定义状态,不如定义$dp[i][j]$表示$[i,j]$未删的最大值,转移就很自然了 转移: 从左边删$dp[i][j]=max(dp[i][j],dp[ ...
- Luogu5324 BJOI2019删数(线段树)
考虑无修改怎么做.对于1~n的每个数,若其存在,将最后一个放在其值的位置,剩余在其前面依次排列,答案即为值域1~n上没有数的位置个数.带修改显然记一下偏移量线段树改一改就好了. #include< ...
- [Luogu5324][BJOI2019]删数(线段树)
CF风格题,先猜结论,记数列中i这个数共出现了cnt[i]次,那么所有区间[i-cnt[i]+1,i]的并集的补集大小就是答案. 于是我们只需要线段树维护每个位置是否被某个区间覆盖到即可,对于整体加减 ...
- 【LOJ】#3094. 「BJOI2019」删数
LOJ#3094. 「BJOI2019」删数 之前做atcoder做到过这个结论结果我忘了... em,就是\([1,n]\)之间每个数\(i\),然后\([i - cnt[i] + 1,i]\)可以 ...
随机推荐
- ERROR:"org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /config/topics/test" when creating or deleting Kafka operations authorized through the Ranger policies
PROBLEM DESCRIPTION When creating or deleting topics in Kafka, they cannot be authorized through the ...
- elasticsearch6.x集群环境部署
elasticsearch集群部署安装jdk chmod 755 jdk-8u161-linux-x64.tar.gztar -zxvf jdk-8u161-linux-x64.tar.gzcp jd ...
- Java获取Linux和Window系统CPU、内存和磁盘总使用率的情况
这是一个工具类,获取的内容: CPU使用率:得到的是当前CPU的使用情况,这是算出的是两次500毫秒时间差的CPU使用率 内存使用率:[1 - 剩余的物理内存/(总的物理内存+虚拟内存) ] * 1 ...
- ginput函数用法
1.ginput函数:获取指定点坐标值 2.用法说明 (1)[x,y] = ginput(n) 函数从当前的坐标轴上选择n个点,并返回这n个点相应的坐标值(x,y).这n个点可由鼠标定位.用户可以按下 ...
- Nonlinear Component Analysis as a Kernel Eigenvalue Problem
目录 引 kernel PCA kernel 的选择 性质 一些问题 代码 Scholkopf B, Smola A J, Muller K, et al. Nonlinear component a ...
- [题解]ybt1365:FBI树(fbi)
ybt1365:FBI树(fbi) [题目描述] 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串. FBI树是一种二叉树,它 ...
- Python3中如何解决中文乱码与编码的问题
1.解决乱码问题: pyhton中内部所有编码是Unicode,中文是gbk:正常情况下,我们输出的是utf-8: 我们可以采用sys.getdefaultencoding()查看系统默认的编码: 解 ...
- Java 关于cannot resolve symbol 'log'报错问题
我用的是IDEA,报错的内容是:cannot resolve symbol 'log' 如图所示: 解决方法: 1.安装插件:Settings→Plugins,输入lom回车: 2.然后选择Insta ...
- spring整合redis使用RedisTemplate的坑Could not get a resource from the pool
一.背景 项目中使用spring框架整合redis,使用框架封装的RedisTemplate来实现数据的增删改查,项目上线后,我发现运行一段时间后,会出现异常Could not get a resou ...
- PHP开发高可用高安全App后端
基于thinkphp5开发的APP,涵盖阿里大于,七牛云图片上传,RestfulApi,短信验证, 需要联系我:QQ:1844912514