【NOIP 2017 提高组 Day 2】列队(蒟蒻的题解)

这道题是几个月前写的了,那时候还是初学线段树,看到这种题的时候简直懵逼。
题面链接

我们通过推样例就可得知,当前若有一个人请假,那么整个二维数组改变的只有当前这一行和最后一列。

如果按最暴力的思路,那我们想的可能会是怎么把当前的代号移到二维数组的最右下端,然后让被影响到的代号归位。但是,这样做显然费时费力,那么,再转念一想,我们可不可以不移除,而是进行标记,具体操作就是不改变二维数组中每个数的原始位置,而是在被移除过的位置标记一下flag,意味着此位置已经没有用了,然后在当前这一行末端接上一个数,在最后一列末端也接上一个数,即为完成更改。

思路大致如此,接下来,我们需要考虑的就是,要如何去实现这个思路。

小数据的话,我们可以用二维数组来记录,但起不到什么大作用;再想一下,也许我们可以用map来记录,但是, 9 e 10 9e10 9e10的点的个数先不说,就说map自带的 l o g log log的复杂度,就能让人搞崩溃。
既然这不行,那也不行,那么,线段树!!!

可以想一下,如果用线段树的话,再用上动态开点,空间问题可以很好地避免,而且,q*log(n)的复杂度,似乎也很优。~~

那就具体来谈一下如何用线段树实现吧。我们可以对每行的前m-1个数字存一个线段树,然后再对最后一列开一个线段树,总共是n+1个线段树。可能屏幕前的你会疑问,这不会炸空间吗!!!但是,动态开点可不是盖得,如果最开始还需要建树的话,那就直接炸了。但是动态开点,每一次只会向某一颗线段树里插入一条链,也就是 l o g ( n ) log(n) log(n)个新节点,一共 q ∗ l o g ( m a x ( n , m ) ) q*log(max(n,m)) qlog(max(n,m))个点,也不算太多。

至于为什么要让最后一列独自美丽:因为每一次移除,都要从最后一列中挑出一个数,再加进去一个数,其特殊之处,需要我们再开一颗线段树。

对于每一行所开的线段树,它们的初始状态即为编号的初始状态,在操作时,我们不会将此序列中的数移除,而仅仅是标记,并在最后加上一个未知的数。我们开一个size数组,存当前节点所代表的区间中有多少个点被移除(找真实位置的时候需要)。

我们每次在线段树中查找时,会找到你要查询的第x个数在此序列中的真实位置y(因为标记过的位置即意味着此位置无用)。若是 y < = m − 1 y<=m-1

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值