学习日记17

61 篇文章 1 订阅
24 篇文章 0 订阅

      今天继续看了一些题解,继续学习了一下树状数组。有关树状数组的各种题目类型,在学习日记15中,已经总结的差不多了,因为那是第一天看树状数组的题目,并且基本看完了一个人写的所有有关树状数组的博客,在之后的学习和看题解的过程中,我又发现了新的题目类型,还有之前的题目类型有的需要扩充,当时认知有限,总结的不够到位。现在补充一下。

一。离线操作预处理。

这个和素数预处理差不多,都是要先把数据存在一个数组里,然后直接可以随便调用,但这里是直接全部输出。

一般情况下这种题会用到结构体,并且都与区间有很大关系。

比如一道题是,在一段数据中,求一个区间内,不重复的数的和。

vis[ k ]代表的是k上次出现的位置,也是判断是否进入数组的依据。

这个时候就要用结构体吧每个区间都记录下来,q[ k ] . l   ,q[ k ] . r    q[ k ] . id  ;

然后按照 r 的大小从小到大进行升序排序。

然后,有几个区间就要循环几次,求几次  ans [ id ]  代表的是不重复的和。

就是把每一组区间循环一边,找出每个区间的ans。

每次循环都是从上一次循环结束的位置开始,到这一次位置的 r 位置。

循环里面有一个while  +  if 判断,while循环 调出数据  a[ k ],if 判断的是这个a [ k ]是否进入过数据如果进入过,就要add(vis[ a[ k ] ] ,-a[ k ]) ;

不管有没有进去过,都会执行下面的操作。

                                      vis[ a[ k ] ] =k;

                                      add(k ,a[ k ]);

每次一个区间循环结束都会把数据存到一个数组里。

                                                                   ans [ q[ k ] . id ] = sum(q[ k ] . r)- sum(q[ k ] . l );

最后循环把所有区间的和输出就可以了。

由于我写的这个内容的笔记,都是汉字写的,很少代码。这里也就都用汉字说明了。


二。二分和树状数组。

由于树状数组本身的特性,递增的,所以它是可以被二分的,这也就使得在使用了二分之后的树状数组效率更高。

有个题是,很多牛都有号码,连续的,给你一串数,代表的第k 位置的牛前面有多少比它小的号码。要求输出牛的号码顺序。

这个题从前面看,看不出,如果倒着看,最后一个数前面比他小的数的个数 n 有了,那么这个号码是多少已经确定了,n+1。所以从后面推到前面就很简单了。

可以用树状数组把1  到n 的数存入树状数组,然后倒着寻找号码,每次寻找号码都用二分。把树状数组的1 到n二分,能够很快的找出来,要不然数据量大了之后容易超时。

应该有的题目二分的对象不一样,目前还未看到这种题目,估计快了。


三。计算连续上升或下降的n元子序列的数量。(对前面的补充)

先把学习日记15中的内容引入。

              连续上升或下降的n元子序列的求法。(这里说四元上升子序列)


可能用到的知识点   1.离散化(如果数据过大)2 dp(当n>3)时,比如现在是四。3 树状数组  (n个)  4 高精度(如果64位都不够用的话)

输入数据为a[ i ]。

下面的   x  y都是a [ i ] 。。。  sum()不是树状数组的函数了,是对里面的所有符合条件的数组求和。

dp过程

dp[ x ][ 2 ] = sum(dp[ y ][ 1 ]);

dp[ x ][ 3 ] = sum(dp[ y ][ 2 ]);

dp[ x ][ 4 ] = sum(dp[ y ][ 3 ]);

其中dp[ x ][ 2 ]  表示的意思是,x为子序列最后一个数字时的二元上升子序列的个数。

因为所有的3元都是来自于之前的二元,所以可以用这个来实现。

其中的树状数组有n个,每次输入一个数据,都需要对所有的树状数组进行更新。


这种求法,只能求规定的元数的子序列。这里的数目较小,如果元数  比较大的话,可以用一个循环来代替,一遍遍的写这个dp过程。
就是把其中的数字换成一个变量 k。
for(int k=2;k<=N;k++)
{
      dp[ x ][ k ] = sum(dp[ y ][ k-1 ]);
}
这样的话,求解很多元的也可以轻松应对了。
还有,如果这个题,再变一下,变成求解上升子序列的数目,那,只需要把dp公式再改一下,就可以了。
         dp[ x ][ k ] = sum(dp[ y ][ j ]);其中 j<k.   sum()是对里面的所有符合条件的数组求和。

这样的话,有关上升序列,下降序列,要求多元,少元,一般这类题都可以求解了。


四。树状数组和搜索  dfs()。

一般这类综合题,分开每个知识点考察的都不是很难。
这种组合,一般是用dfs,求出区间或者点,然后再用树状数组求和。可能单独用一个时间不允许。

由于我没整理这种题的笔记,这里就不举例了。








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值