首页 > 技术文章 > 雅礼集训 Day3 数据结构

lcyfrog 2020-06-14 21:32 原文

雅礼集训 Day3 数据结构

均值法

根号算法的本质是让两部分的复杂度接近从而使总复杂度最小,这在我们学线段树的时候比较前缀和和差分是一个道理。这种让两端复杂度均衡来达到最优的方法就叫均值法。

例题:舌尖上的由乃

  1. 区间加
  2. 区间k大

首先有个朴素的做法:每块维护排序后的序列,每次二分答案并判定,散块暴力,整块在排序后的序列上二分,块大小取 \(\sqrt n\),复杂度是\(O(n\sqrt n\log^2 n)\)

然后分析一下把块大小取\(\sqrt{n\log n}\)可以做到\(O(n\sqrt{n\log n}\log n)\)

其实修改的时候散块不用重构,直接归并即可。散块查询也可以先提出来再二分,总复杂度\(O(n/k\log^2n +\log ^2n+k)\),当\(n/klog^2n=k\)的时候最优,为\(O(n\sqrt n \log n)\)

莫队算法复杂度

设块大小为k,每块内右端点单调,每次跨块右端点最多O(n)移动量,因此复杂度是\(O(n^2/k)\)
跨块均摊左端点改变量是k,在同块内每次左端点移动量不超过k,因此复杂度是\(O(mk)\)
总复杂度是\(O(n^2/k+mk)\)

\(k=n/\sqrt m\)时复杂度最优,为\(n\sqrt m\)

杜教筛也运用了均值法。

Gty的二逼妹子序列

Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
为了方便,我们规定妹子们的美丽度全都在[1,n]中。
给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl...sr中,权值∈[a,b]的权值的种类数。

莫队+线段树,注意到莫队查询只有\(m\)次,而添加/删除是\(n\sqrt m\)次的,那么我们权值分块即可做到\(n\sqrt m+m\sqrt n\)(这能过???)

根号算法的互相结合

[hackerrank]Range Modular Queries

一个序列,值域是40000,每次区间询问模x等于y的数有多少个。
n<=40000

之前好像做过...

考虑对值域根号分治,\(x\leq 200\)的直接分块,处理\(200*200*200\)的前缀和+暴力。

\(x\geq 200\)的使用莫队,每次暴力在桶里找即可,容易证明每次询问\(O(\sqrt n)\)

"区间第k小"

给你一个序列元素均在[0,n)内,并给定常数w。
每次在线询问区间第k小,要求忽略区间出现次数>w的数。

n<=100000

离线可以莫队+维护一个值域分块和桶,>w的时候处理一下即可。

现在要求在线,考虑为什么要莫队,因为我们想要得到一段区间的值域分块和桶。这个时候就要掏出分块套分块了,我们把序列分块,处理出第i块到第j块的值域分块,剩下的暴力加进去。

麻烦的是桶不能这样做,但是我们并不需要知道一个区间的桶,具体的我们只需要知道一个数在一个区间的出现次数,这个可以预处理每个数在前i块中出现了多少次,然后只需要对剩余部分暴力维护出桶。

对于>w的处理,可以先搞出桶再暴力搞值域分块。

[hdu6079]Yuno And Claris

一个序列,支持两种操作:
1、区间内值为x全部变成y。
2、区间询问第k大。

n,m<=100000

我们可以将序列分块,对前缀块维护值域分块,现在问题是修改时的整块和散块,以及查询时的散块。
也就是我们要怎么操作才会获取每个位置是什么数?
对于每个块,每种数值维护一个链表,表示这种数值的所有位置,按任意顺序链接即可。
当对于整块执行了一个x->y时,直接把x的头接在y的尾上。
散块执行时,直接分裂出来接到y最后。
散块查询时,直接暴力扫所有链表,得到每个位置的数值。
复杂度\(O(n\sqrt n)\)

分块算法上树

子树分块

直接dfn序上分块。

链分块

随机\(\sqrt n\)个点为关键点,然后将关键点形成的虚树建出来,每条树边就是一个块。
没有被归入任何块的,那就当做散块。块数显然是\(O(\sqrt n)\)的,而且可以发现散块暴力期望长度也是\(O(\sqrt n)\)(不会证)

后记

后面还有一些杂题,自己看了看,就不写了。

推荐阅读