分治与分块
重制版笔记,很多地方还留了坑。。
其中穿插了重量平衡树
分治
CDQ 分治
本质上是考虑左边对右边的影响,问题变成了先加入再查询的问题
离线算法
处理 D 维数点时间是$O(nlog^{D-1}n)$
D 维数点用KDTree:$O(n^{\frac{D-1}{D}})$
D 维数点用Bitset:$O(\frac{Dn^2}w)$*
加点,给定$a , b$查询最大的$ax+by$
本质上是维护动态凸壳 *
直接set维护
记录全局变量,做插入的时候按照 x 比较,做询问按照斜率比较
因为set里面x递增,斜率也递增
CDQ 分治
solve( l , r ) ,先 solve( l , m ) solve( m + 1 , r )
然后就变成了静态问题,左边点加进去,右边的询问。
静态凸壳!
右边斜率排序,然后类似归排扫一遍就好了。
CF 848C
维护每个数字的位置和上一次出现的位置,价值是 i - pre i
一段区间的价值就是$\displaystyle\sum_{l\leq i \leq r , pre[i] \geq l} i - pre[i]$
本质上类似差分
修改本质上只会修改 pre 指向这个点的,这个点,还有它的prev,只会改变三个值。
带修改的二维数点本质上是三维数点,时间是一维。$O(nlog^2n)$
可以写一下
分治FFT
前段时间学过吧
uoj 50
求解微分方程$f’(x) = f^2(x) p(x) + 1$
算出来的式子是$\displaystyle \frac{1}{n} \sum_{0\leq i+j\leq n-1} f_if_jp_{n-1-i-j}$
分治吧,貌似就是分治fft套路
先solve( l , m )
然后考虑新求出的左边的值对右边的贡献
然后就要用$f_{l…mid} f_{0…r-l} p_{0…r-1}$卷起来
然后就把$m+1…r$更新进$f_{m+1…r}$
式子可能有点小锅(比如+1-1啥的),需要再推一下。。
线段树分治(暑假讲的叫时间分治)
离线动态图连通性
把每条边的存活时间放到序列上,然后就可以在线段树上dfs,撤销并查集解决问题
这里要按大小合并,才可以让撤销的量很少
可以LCT维护删除时间的最大生成树,也是离线
对每个物品,求不包含它的背包 方案数
线段树分治
solve( l , r , f ) f 表示 把$l , r$外面的物品加入的数组
$f_1$表示$f$中加入 mid + 1 … r 的物品
$f_2$表示$f$中加入 l … mid
然后递归下去$O(nwlogn)$一个物品会被加入$logn$次
城市建设
修改边权,求MST和
还是可以对时间建立线段树,求出每个边存活时间
LCT 一个 log,线段树分治一个 log,很慢,不需要动脑子
修改一条边边权实际上只会影响MST一条边
随着修改MST变化是很少的
$solve(l,r)$表示$l , r$的修改
整个MST只会改$O(r-l)$边,其他大多数边是不变的
能不能把会变的边拿出来跑MST?
假设边集(l…r修改的边)是$S$,先把其中边设置为 +inf
把这些边和剩余的边跑MST,然后现在不在MST中的边就可以删除了。
因为这些边只会变小,只会把MST的边给拖出来
现在边数边成了$O(n + |S|)$
然后再设置成 -inf,再跑一次MST,现在在MST中的边一定最后也在MST中
点数变成了$O(|S|)$,因为这些边已经可以用并查集并起来了。
而$n$其实是上一层的点数,也就是$O(2(r-l))$
所以这一层的复杂度也是$O(r-l)$的
$T(n) = 2T(\frac{n}{2}) + O(nlogn)$
$O(nlog^2n)$这里的 log 是排序
有点难写吧(可以写一下
核心思想:修改影响的边数量很少
二进制分组
二项堆
一种可并堆,和二进制分组的思想类似。
$T_k$表示的堆是$T_{k-1}$再挂了个$T_{k-1}$,然后节点数量就是$2^{k-1}$
11个数字的二项堆就是一个点数为 8+2+1的森林
合并两个二项堆就是类似二进制+法。
合并是$log$的
删除元素,其实也是合并,比如从16的堆删除就是 1,2,4,8, 的堆和剩下的堆合并。
维护向量序列,支持末尾加入元素,末尾删除元素,求$l,r$和$(x,y)$的最大点积
二进制分组解决的问题往往是,重构很简单,插入删除很麻烦的东西。比如凸壳这种东西,重构直接做,但是插入删除很难。
如果只有增加的话,加入当前有21个元素,我们记做三组 16 + 4 + 1
每组都建一个数据结构,支持区间查询,并且重构很快(线性就很优秀),插入删除很慢。
你往后面加入一个元素,就和前面一步一步合并(重构)过去,比如刚刚那个21的例子,加入一个元素就是 16 + 4 + 2
这样的结构数量必然是$log$,如果在某个结构查询复杂度是$Q(n)$那么查询复杂度就是$Q(n)logn$
重构的复杂度假如是$n$那么每一个元素最多会被重构$logn$次,所以,总复杂度是$nlogn$
重构是均摊$logn$的
既然支持区间操作,可以对每个区间建个线段树,暴力build线段树也是$nlogn$
复杂度是$nlog^2n$的
其实也可以看作建了一棵大的,点数是2的次幂的线段树,当一个点下面的所有叶子都被填了值才把它建出来。本质上是一样的。
二进制分组怎么删除呢?其实整个序列如果画成一棵树的样子(大概就是版本树之类的?)删除就是往父亲跳,加入就是新加儿子。所以问题本质上就是给你棵树,求某个点到根上的一段的点积的最大值。
树剖是$O(nlog^3n)$对询问排序可以去一个log,反正好像不优秀
题解做法好像是点分
直接线段树强行搞是不行的,你删除一个插入一个….在一个块的左右反复横跳就挂了
其实可以搞成随机的,每个点随机一个权值如果比上一个小就合并。
对于一个块被建出来,如果这个块有东西被删除了,就记个标记表示这个块是坏的。
查询如果查到一个坏的块(节点)就到左右递归继续查。
我们希望保证每层只有一个坏的块
如果结尾一直在最后那个坏块动来动去没啥问题
但是如果你的结尾移到了前一个块,那么意味着最后面那块被删光了,那么还是只有一个坏块
但是如果结尾移到了后一个位置,下一个块被建了,那么我们可以直接重构前一个块。
还不是很明白,想清楚了再继续写吧。。
整体二分
子矩阵查询 kth n 500 q 50000
直接二分的话,需要查询子矩阵比某个数大的个数
整体二分,就是拿所有询问一起二分
我们需要看哪些询问权值是大于$\frac{w}{2}$的,哪些是小于等于$\frac{w}{2}$的
这个比较简单的方法是把小于等于$mid$的标1,然后前缀和
然后我们就把询问分成了$0…\frac w 2$,$\frac w 2 + 1$
就这样分治下去
但是每一次分治$n^2$肯定是不行的,必须做到每层$n^2$
每次分治其实我们只需要把$l…mid$加进去然后做查询
对于每个询问就是二维数点的问题。
其实貌似顺次递归来做,就直接是对的了吧。。
所以对于分治到$l,r$复杂度就是$O(|A|+|Q|logn)$$A$为这里的点集
复杂度是$(n^2+Q) log^2(n^2)$
单点修改区间 kth
二分到$l,r$把一个数字从$a$到$b$就是$x$这个位置 少$a$多$b$
可以看自己以前的代码吧$nlog^2n$的
ZOJ2112 这题由于空间限制只能整体二分
给$l , r$的vector 放进去个 k 求 l , r kth
整体二分就变成区间+了 貌似就是那个 任务查询系统 以前挂了好久的题
CF 102354 B
给定 a , b 两个1…n 排列,求$c[k] = MAX_{(i,j)=k}|a_i-b_j|$
$c[k] = MAX_{(i.j)=1}|a_{ik}-b_{jk}|$
其实我们只要求了$c[1]$问题就解决了
因为$c[k]$本质 就是$a_k,a_{2k},…,a_{\lfloor\frac n k \rfloor}$和$b_k,b_{2k},…,b_{\lfloor\frac n k \rfloor}$来跑$c[1]$
枚举$i$就要求最大的$b_j , (i,j) = 1$,因为最大最小是对称的我们求最大的就好了。
整体二分,分治到$(l,r)$,就是知道$a_i$的最大的值在 l,r 间。
我们按照 值在$mid + 1…r$的下标是否存在与当前$a$互质的把$a$分成两份分别跑二分下去。
然后问题就是,统计值在$mid + 1 … r $的下表$j_t$是否存在与某个下标互质。
对于$a_i$下标$i$,需要统计
莫反一下
然后我们可以枚举$d$,给每个$d$统计一下在$A$里面的倍数个数,并且把$\mu(d) \times cnt$放到作为它倍数的$i$里面。这题可以写一下QWQ
决策单调性
由于没怎么写过决策单调性,可能有很多问题QAQ
就是存在最优的方案决策单调。一般都是打表找的规律。
首先,四边形不等式$w(a,d) + w(b,c) \geq w(a,b) + w(c,d)$
假设有$i , k , l , j$, 如果决策不单调意味着$i$转移到了$j$而$k$转移到了$l$
如果满足了上面那个式子,相交的两条边优于了包含的边,所以就满足了决策单调性。这大概就是实质了吧?
四边形不等式是 $O(n^2)$的而不是$O(nk)$准确的说是$O(n(n+k))$
同时,四边形不等式可以优化二维dp的转移,
满足四边形不等式后,假设$dp[l][r]$决策点是$p[l][r]$,那么
其实本质就是交错的路径优秀于包含的路径
但是还要注意,虽然四边形不等式可以推出决策单调,但是决策单调不能推出四边形不等式。
CF 321 E & 诗人小G (其实没怎么听到题的做法,听了决策单调性优化dp的实现方法)
下面是几种搞决策单调性的方法
这里可能还需要再听一下
$solve( l , r , p , q )$表示 i 再$l , r$最优决策是$p , q$之间
我们可以先算$mid$位置的决策点 op 然后,就可以
$solve(l,mid,p,op) , solve(mid+1,r,op,q)$
这样复杂度是$O(knlog_2n)$这样不容易挂。
其实也可以二分单调栈。考虑我们如果求出了$dp[1]$那么后面最优都是从 1 转移过来
现在求出了 2 , 从 2 转移最优的构成了一个后缀。于是我们可以用单调栈维护每个点可以决定的区间。先从后往前找看能不能整个替代,到达具体区间后再二分。复杂度也是一个$log$但但是不如前一个好写。
其实是可以$O(nk)$的,然而我看不懂 SMAWK
CF 868 F
暴力分治,$solve( l , r , p , q )$
分治下去的时候端点的移动总量是$O(r-l+q-p)$级别的。
把指针从$p$移动到$mid$并且不断更新每个数字的出现个数,同时不断算 答案并且更新。
建议看这个学一下再
IOI 2013 wombats
假设是朝右朝下吧,不是很影响 对于 R 这一维建立线段树
决策是具有单调性的,路径有交叉可以通过调整变短
如果结束点从上往下走,那么中转点必然也是从上往下走的
复杂度是$O(c^2logclogr)$
建议看这个
IOI 2014 holiday
首先,肯定不会反复横跳
然后,结论就是$r$关于$l$是决策单调的。
不太会证,这里引用下钟神的证明:
设某个区间$[l,r]$的答案为$w(l,r)$。
考虑反证,设$l$的最优右端点为$r$,$l+1$的最优右端点为$r’$,且$r’ < r$。
那么我们有:
两式相加得到
即
显然是不成立的,因为上述式子的意义实际上是将$(r’,r]$的元素加入$[l,r’]$或者$[l+1,r’]$,带来的额外的贡献。由于加入的元素是相同的,而$[l,r’]$它可以去玩的天数更少,所以
WQS 二分
也就是常说的凸优化
这个东西有关的证明我是都不会的,往往看到$O(nk)$过不去十有八九就是凸的了。
Tree
我们考虑给所有白色边加权,通过调权值可以让最优策略的白色边个数变化。
通过二分调整权值使得最优策略正好需要need个白边
什么情况这样二分正确呢?如果代价关于个数的图像是凸的
若$f(x)$表示选择$x$个白边(上一个题)的代价
条件就是$f(x+1) - f(x) \geq f(x) - f(x-1)$
咋证明,我也不会,只会感性理解QAQ
邮局
如果权值满足四边形不等式,那 f 一定是凸的。
所以二分权值,然后用那个单调栈的方法dp一下
复杂度是$O(nlognlogv)$
—- 开始掉线 —-
因为轮廓线dp实在不会啊(
第二天讲了环版本
还是不会
Rikka with K-Match
没看太懂,后来再康康吧。。。wsl
林克卡特树
二分,搞个额外代价,虽然不会证明,但是它确实是凸的
一般$O(nk)$过不去都是凸的(确信)
一个经典题
操作A串(添加,删除,修改)使得AB循环同构
不循环重构
就是个$O(n^2)$dp
$dp[i][j]$可以由$dp[i-1][j-1] + c_M$,$dp[i-1][j] + c_A$,$dp[i][j-1]+c_d$转移得到
这个可以看成是平面图上的最段路
路径上的每个点当成决策点,对起点分治,找$0,\frac m 2$到$n , \frac m 2$的路径。
这个路径上半部分的点只对上面的起点有用,下半部分的点只对下半部分的起点有用
然后就可以分治下去做
这大概就是广义的决策单调性 , 不仅可以用于dp
(这里也很晕)
循环同构复杂度是$n^2logn$的
图分治
没听到,起晚咕了,貌似只讲了几分钟,,,有时间回来补吧
树分治
点分治
最普通的树分治。每次选择重心向下分治就好了。不会超过$log$层的。
链分治
三度化
然后必然可以选择一条边,使得接下来剩下的两个树$size$最大是原来的$\frac 2 3$加一。
好处在于,链分治后你每次只需要merge两个子树的信息,比较好写。深度也是log的
点分治题目的几个做法
比如,路径长度不超过$k$的路径条数
容斥
每个点单独排序算,容斥减掉
这个题就是,任意选择两个点长度不超过$k$减去来自同一子树不超过$k$
可以分别sort一下再总sort,双指针解决问题
如果不能容斥 逐一加入
每加入一个子树,求这个子树中的$v$使得$dis[v] \leq k - dis[u]$
可以BIT维护
用哈夫曼树的方法,每次合并最小的两个儿子
假设合并复杂度是$O(S_i+S_j)$
这样一直合并最小的,复杂度也是对的 带log
一个位置的合并复杂度是 一个 log总复杂度两个log
问多少点对之间构成路径是合法括号序
点分治,
最终要满足的必然是$u$到$r$的路径只剩下了一些左括号了,$r$到$v$只剩下一些右括号了。
问距离为素数的点对(距离为 1 ~ n ) 的点对
还是考虑是否经过分治中心
每个子树写成生成函数$p_i$的形式,$a_k$表示有多少个深度为$k$的
要求的是$\displaystyle \sum_{i\neq j} p_ip_j$
可以$\frac{(\sum p_i)^2-\sum p_i^2}{2}$容斥做
树上背包
给定一棵树,每个位置都有容量和价值,选一个联通子树使得体积和小于等于$V$重量和最大。
如果确定了选根,那么你总是需要合并两个背包然后人就没了
先按照 DFS 序排序后,子树总是一段连续区间
$dp[i][j]$考虑$i … n$这段物品,考虑一个物品选了,在下个物品继续选择$dp[i+1][j-v_i] + w_i$
如果一个物品没选,必须把整个子树跳过$dp[r_i][j]$
这样可以处理根一定被选择的答案,复杂度是$O(nV)$
根不一定被选,所以套一层点分质就对了。
复杂度是$O(nVlog)$
一棵树,每个点还是有代价和权值,选择一些物品,使得它们不在树上相邻。
求出这样的东西的背包
$n \leq 100 , V \leq 10000$
复杂度是$n^2 V$
考虑点分,按照点分治选择根的顺序标号,考虑$dp[i][j][S]$前$i$个物品,容量和是$j$,前面每个物品选没选是$S$(集合)这样算法复杂度是$nV2^n$
但是实际上前一个子树不会影响后一个子树,所以我们不需要知道每个点是否被选只需要记录点分中心是否被选。所以$S$只需要记录这个点到根的路径是否被选,$S$是$2^{log}$,复杂度没问题。
HDU6556 可以写一下。
点分树
点分治过程中形成的树,可以方便处理带修改的问题。修改的处理往往是从一个点向上跳(只有 log 层)
BZOJ 3730
对于所有$x,r$求$\displaystyle \sum _{dis(v,x)\leq r} b_v$
点分,分$x$到$v$的路径是否经过中心讨论。
考虑跨过中心的话,
现在要求的其实是$dis(v,T) \leq r - d_x$的点 - 在$x$子树中$dis(v,T) \leq r-d_x$的点。
对于每个$T$记录小于等于$k$的权值和。
怎么加修改呢?我们对于每个点都仍然记录了小于等于$k$的权值和。我们可以用一个大小为 $O(size)$的BIT记录这个,这样小于等于$k$就是前缀查询。
如果一个点被修改了,到它的所有点分中心都要被修改。
这些点分中心分别单点改就好了。
Qtree 4 / zjoi Hide
边分治可能要简单一点,因为每次只用处理两个部分
先三度化,然后选择一个边切掉,考虑两个黑点是否经过分治边。
其实就是这个边两端的最远距离。分治的时候分别记录边两棵子树所有黑点到根的距离
由于支持点修改,可以每个分治中心搞个 multiset 维护
外部再开个multiset表示每个分治中心对答案的贡献。$nlog^2n$
其实有单log做法的
可以先把欧拉序写出来,然后$q$$p$的距离就是$dep[q]+dep[v]-2\min\{dep[r]\} ,q\leq r \leq p$
直径就是要加个$max$
所以就是$\max\{dep[p]+dep[q]-2dep[r]\},q\leq r\leq p$
所以其实就是要找给定欧拉序,整个序列要选择三个位置,第一、三个位置贡献是1,第二个是-2,使得权值尽量大。线段树记录一下$p$在这个区间,$pr$都在这个区间,$r$在这个区间…这些东西。然后这个是可以 pushup 的
给定一个树,每个点有权值$a_i$,修改$a_i$,查询$\min_u \sum a_i dis(i,u)$
每个点度数不超过20(其实没有貌似也可以做,三度化一下嘛)
当这个东西取到最小,$u$必然是重心。如果是重心每个子树的和都不会超过$\frac {\sum a_i} 2$。因为如果不是重心,我们明显可以往多于$\frac S 2$的儿子走,这样一定可以让答案变小。
所以要求的其实是一个带权重心。
单独求这个其实很简单,如果所有子树都不超过一半就是这个点,否则往多于一半的儿子走就好了。
建立点分树,我们递归下去后一个子树是这个递归下去的子树的大小,但是我们需要维护的是这个子树在全局意义下的大小。如果我们当前在$T_1$我们要进入$T_2$我们就把$T_1$的重量全部挂到$T_2$的某一个分支。就是把对应的子树的权值加$w$,做完了再减掉就好了。
CF 566C
给定i一棵树$\min_x \sum dis(i,x)^{1.5}$
$f(x) = x^{1.5}$是凸函数 加几次都是凸函数,所以$G(x) = \sum d(x,i)$也是凸函数
还是找一个点分治的重心,看它往哪边跳会变大。必然只有往一个方向走会变小,因为如果有两个方向走可以变小,那么一定不是凸函数。
如何找到往哪个方向会变小?这里做法是求导,假设 第$i$个子树的根是$rt_i$这个子树内所有点的导数的和是$p_i$那么往这个方面走是$\sum p_j - 2p_i$,需要找到唯一一个方向,使得导数是负数的方向走
具体看 这个 吧
动态点分治 紫荆花之恋
添加叶子,维护点分树的结构
点分树的结构是很容易变的啊(添加叶子时)
所以我们维护的不是严格的点分树,而是每个点的儿子要小于等于$\alpha n$的,$\alpha $一般取 0.8~0.9
这样整个树也是一个log级别的
但是我们一直往一边插入节点,明显会变得不平衡
所以如果某个子树不平衡了,dfs这个子树并且重构一边就好了,其实和替罪羊的pia操作一样
复杂度分析也是和替罪羊一样的
重量平衡树 带插入区间 kth
(从分治与分块自然过渡到数据结构?)
重量平衡树要做的事情是,一个点插入影响的子树只有$O(logn)$的(不管是期望,严格之类的)所以splay修改的子树大小是$O(n)$的。就是一个点插入后需要更新的个数是 log 的
只有这样可以方便的套其他树
重量平衡树: Treap,替罪羊
做这个大概就是替罪羊套 线段树
应用:有个序列,可以在log的复杂度插入,O1比较两个数哪个在前面
对于每个点我们维护一个区间,比如根节点是0,1,根的左儿子是$0,0.5$右儿子是$0.5,1$
这样的话直接插入可能导致一些问题,可能精度不够或者退化$n^2$
所以需要重量平衡树比如替罪羊的同构
分块
分块实质上可以看成一个$\sqrt n$叉树
引入:区间+区间求和
分块:大小 sqrt n 分成若干块 整段打标记,零散暴力
区间求和就一样
$O(m\sqrt n)$
区间+ 区间小于 x 的个数
还是先分块 对于整块+ 就打标记,零散块直接+
查询两头暴力 for ,块内维护了有序的序列,一个 log
块大小设$\sqrt{nlogn}$
区间 + 查询区间 kth
外面再套个二分。
直接做的话
查询,是$\frac n T log^2n + Tlogn$
修改,是$\frac n T + T$
直接做是$\sqrt n log^{1.5}$不太行
可以把$T logn$这部分优化成$T + logn$因为可以先拿零散块归并一下
这样就可以$T = \sqrt n logn$
根号平衡!
优化复杂度利器
-$O(1)$修改,$O(\sqrt n)$求和
直接分块做
-$O(\sqrt n)$修改,$O(1)$求和
每个块内部维护前缀和,维护整块前缀和
反正类似这个的问题都是可以根号平衡的
-$O(1)$插入$O(\sqrt n)$查询 kth
值域分块
查询 kth 貌似变成了一个找前缀和大于 k 的问题。遍历块即可。$O(\sqrt n)$
-$O(\sqrt n)$插入$O(1)$查询 kth
数字从小到大排序,每块大小都是$T$级别的
插入一个位置,对后面每个块都是前面插入一个,从后面pop一个
其实就是块状链表吧?
查询 kth 就直接查就好了。因为每个块大小固定
给定$n$个数,和$m$个函数,每个函数是$l_i,r_i$数的和
每次询问:
1 把第x个数字变成y
2 求 x…y 函数的和
把函数分块,维护每块函数的和,然后就是求两头额外函数的和。
预处理每个数字对一个块的贡献是多少
修改是$O(\sqrt n)$的。
用前面那个平衡的方法,是$O(m\sqrt n)$的
莫队
做那种可以快速支持插入删除,但是完全不能支持信息合并的问题
当然有些时候也不可以删除,这种情况是回滚莫队
引入:区间内所有数字出现次数的平方和
插入删除明显$O(1)$
做法是对所有询问分个块(按照$T$)
每块的询问按照左端点所在的块,右端点从左往右走
这样看起来复杂度就很$\sqrt n$
复杂度就是$O( n\sqrt m )$我也不知道为什么。
块大小$O(\frac {n}{\sqrt m})$
一个优化
奇数块从小到达,偶数从大到小
右端点是来回跳的,快一些。
(科学研究表明)最快 的 块大小$\frac n {\sqrt{\frac 2 3 m}}$
查询区间值在$[a,b]$内的不同数个数
跑莫队维护树状数组,复杂度是带log的根号
我们可以运用添加$O(1)$查询$O(\sqrt n)$的根号平衡,复杂度是一个根号。
BZOJ 3920
给定一个序列,查询区间中出现次数$k_1$小的数里面$k_2$小的数
先离散化,比如 $x$出现了$cnt_x$次,把$(1,x),(2,x),…,(c,x)$离散化,每次加一个数进来,就是加一个$(c+1,x)$进来。
查询就是利用前面那个修改$O(1)$查询$O(\sqrt n )$kth 的根号平衡
LOJ 2874
一个数的权值是它出现的次数 * 数值大小,查询区间中最大的权值
对于所有数字 $x$你就把$x , 2x , 3x, … ,cnt x$离散化
然后问题就变成了你要支持维护最大值的莫队
按照权值分块找最大值就可以了。
区间逆序对
最简单的做法:莫队树状数组,带 log
如何去掉log?
我们要做$O(n\sqrt m )$次查询$l , r$小于等于$x$有多少个
如果可以离线,这个就可以做
就是我们可以块状树的方法去做,但是这个查询的区间是在改变的
最暴力的方法是把那个分块结构可持久化
每次做就把修改过的块复制一遍,再把所有块之间的前缀和给复制一遍
但是这个方法也不优秀 常数很大空间也不优秀
因为数组开大了cache读取也很慢
所以有另一种方法——
二次离线莫队
[a,b] [c,d]表示$x \in [a,b], y\in [c,d] , a_x > a_y$的数量
从$l , r$移动到$l , r’$,增加量是
$\sum_{i=r}^{r’} [l,i-1][i,i]$
把$l,i-1$拆成两个前缀的-
增量是$\sum_{i=r+1}^{r’} [1,i-1][i,i] - [1,l-1][i,i]$
左边的东西只跟$i$有关,右边那个加起来是$[1,l-1][r+1,r’]$
现在我们相当于有了$m$个这样的询问
对于这个东西我们再次做一次离线
按照$l$排序,一个一个数字加进去,然后我们就有询问,就可以 for 一下$r+1,r’$来做
这就是第二次离线
很巧妙 啊QAQ
树上莫队
解决一些树上查询的问题
比如一条路径有多少种不同的颜色
怎样写比较简单呢?
用欧拉序,把每个东西进栈写一次出栈写一次
对于 A 点 和 B 点,找到它们在序列中第一次出现的位置,然后把它们第一次出现的位置之间的东西拿出来
把拿出来的数出现了两次的东西都去掉,再把端点和 LCA 胡上去
现在得到的就是这条路径上的东西
这个东西复杂度就是序列莫队(其实就是序列莫队)
就是一个把树上问题转移到链上的做法
带修莫队
莫队上面会有一些修改操作
我们把时间当成一维,两个修改的距离就是三个维度都移动,复杂度是$O(n^{\frac 5 3})$
块大小大概是$n^{\frac 2 3}$
先按照$l$所在块,在用$r$所在块,再用$t$排序
最坏复杂度$n^\frac 5 3$
证明:我不会
Codechef QCHEF
求区间最大的$|x-y|$使得$a_x = a_y$
回滚莫队,就是这种不好删除比较好插入的题。我不太会,上课过的有点快,先咕一会
CF 765 F (由于块太毒瘤突然插入的一个线段树题)
查询区间绝对值差的最小值
$l , r$间的$|a_i-b_i|$的最小值
扫右端点维护左端点的答案
分大于$a_r$和小于讨论
找到靠后第一个比$a_r$大的东西,可以用$a_j - a_r$更新所有$1 \leq l \leq j$的答案
然后找到一个小于等于这两个数平均数的元素
因为如果比这两个平均数大,$a_j - a_k$来得更小,$a_r$不会影响答案
同理一直这样找小于等于平均数的数字
这个可以对值域开一个线段树,每个权值记录它最后出现的位置,每次要查询的是$a_i$前面第一个比$a_i$大的,就是$a_i+1,+\infin$最大的值,然后就变成查询$a_i+1,\frac{a_i+a_j}{2}$的最靠后来更新。复杂度是$O(nlognlogv)$
据说有单log或者双log带修不会
经典问题
点权+,查询$x$相邻的点权和
按照度数 是否大于$\sqrt m$来分类做。
每个点记录下它的小邻居的和,修改小点直接给出去的边修改。
修改大点,直接修改
查询 查大点就好了
复杂度是 根号
树,点权,多次查询,每次给 x y k 求从 x 开始每次跳k个节点到 y 所经过节点的和
按照$k$与根号关系,
大于根号就直接跳,我们可以树剖一下,对于每个链我们记录一下,如果在一个重链上跳是不会有log的 , 长链剖分就没log了
或者我们对于每个点记录它的一级,二级,…sqrt 级祖先,和sqrt , 2sqrt…级祖先
小于根号就是求 x 到 y 路上 深度 % k 为 r 的点权和
x 到根的 深度膜k为r的点权和 dfs的时候拿个数组记录一下膜k为r的点权和为多少
(其实对k很大也可以离线来做的)
复杂度是可以线性的
YNOI 2015 此时此刻的光辉
查询区间乘积的约数个数
暴力莫队,对每个因子记下出现次数,会TLE
本质不同的因子个数不是log个,是 log/loglog 但是还是T了
每个数的大于$v^{\frac 1 3}$的质因数个数只有2个,小于等于$v^\frac 1 3$的质数只有$v^ \frac 1 3log$
v = 1e9小于1000的质因数个数只有168个
维护感觉类似寿司晚宴
树分块
COT 2
树,点权,强制在线,查链颜色数
随机打$\sqrt n$ 个点,可以认为一个点到它上一个被选中的点的距离期望是$\sqrt n$的。
或者用深度是$\sqrt n$的倍数并且它往下的深度是大于根号的点
这样选择可以保证每个点往上$2\sqrt n$必然可以碰到关键点。
我们先预处理出关键点两两间的答案
预处理是从每个关键点dfs就知道了关键点两两答案。
现在就是看某个颜色从某个点到根的出现次数
这个比较暴力好想的做法是主席树,记录某个颜色的出现次数,复杂度是一个log
但是其实可以套用之前的分块结构,修改$n^\frac 1 2$查询$O(1)$的块状树,可持久化一下,这样就可以做到$O(1)$了虽然空间有点菜是$n\sqrt n$