写大分块写的。
难度升序排列。
[Ynoi2017] 由乃打扑克
梦开始的地方。
对块内排序,二分查找。
\(O(n\sqrt {n\log n+\Delta })\)。
[Ynoi2011] 初始化
根号分治板子。就是卡常。
大于 \(B\) 的直接加,小于 \(B\) 的显然可以记 \(f_{i,j}\) 表示所有模 \(i\) 余 \(j\) 的位置加的数。发现这样算的话修改和查询分别是 \(O(1)-O(B)\) 的,所以考虑记 \(pre_{i,j}\) 表示模 \(i\) 前 \(j\) 的贡献,\(suf_{i,j}\) 表示模 \(i\) 为 \(j\sim i\) 的贡献。这样就变成 \(O(B)-O(1)\) 了。对每个 \(i\) 算算贡献即可。
代码不难写,但是 |x| 卡常。
结果我定义 fread fwrite 数组和开大了 pre 和 suf 导致多开了约 1e7 个 char,开着开着 TLE 了。综上所述,fread 不如普通快读。/cf
P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I.
考虑分块。
我们发现一段区间的贡献可以拆为整块对整块、散块对散块、散块对整块。
所以考虑预处理 \(ans_{i,j}\) 表示 \(i\sim j\) 块的贡献,\(sum1_{i},sum2_{i}\) 分别表示块首/块尾到第 \(i\) 个数的贡献,\(f_{i,j}\) 表示前 \(i\) 个数对第 \(j\) 个块的逆序对贡献。设 \(calc(a,b,c,d)\) 表示区间 \([a,b]\) 和区间 \([c,d]\) 的贡献。
则对左右端点在同一块内的情况,答案为 \(sum1_r-sum2_l-calc(l,r,L_{Bl},l-1)\)。
对于左右端点不在同一块的情况,答案为 \(ans_{Bl+1,Br-1}+sum1_r+sum2_l+calc(l,R_{Bl},L_{Br},r)\sum\limits_{i=bl+1}^{br-1}(f_{i,(l\to R_{bl})}+f_{i,(L_{br},r)})\)。
接下来考虑预处理贡献。
对于 \(calc\),显然可以预处理出块内有序数组之后归并。
对于 \(sum1_i,sum2_i\),可以直接在块内用树状数组计算贡献,这部分是 \(O(n\log n)\) 的。
对于 \(f\),对整个序列排序,发现从小到大插入后每个位置的贡献可算,复杂度为 \(O(n\sqrt n)\)。
对于 \(ans\),\(ans_{i,j}=ans_{i+1,j}+ans_{i,j-1}-ans_{i+1,j-1}+f_{j,R_i}-f_{j,L_i-1}\)。
于是就做完了。
发现写的很降智。
降智错误:
-
归并排序把两个数组放进一个了。
-
块个数 \((n-1)/sz+1 -> n/sz\)。
-
使用宏定义使得过慢。
[Ynoi2019 模拟赛] Yuno loves sqrt technology III
记 \(f_{i,j}\) 表示 \(i\sim j\) 的块的答案,这个可以直接做。
记 \(pos_x\) 表示所有 \(x\) 出现位置。
然后对于散块的每个位置,查询他在 \(pos_x\) 中 \(+/-ans\) 的位置是否 \(\le r \ or \ge l\),如果是则 \(ans++\)。显然每次 \(ans\) 只会增加 \(O(\sqrt n)\) 次。
怎么有傻逼强制在线不异或 \(lans\) 的。
[Ynoi2016] 镜中的昆虫
正解是 cdq 分治,但是我们考虑分块!
容易想到一个经典套路:在数颜色的时候只数这个区间里某种颜色最右(左)边的点 。具体地说,我们维护一个 nxt
数组表示下一个和 \(a_i\) 的值相同的数的位置,如果没有 \(nxt_i=n+1\)。那么显然问题转化为求 \([l,r]\) 中 \(nxt_i>r\) 的 \(i\) 的数量。单点修改时,我们可以维护一颗珂朵莉树,二分找第一个和当前位置颜色相同的点即可。这显然是一个带修改的二维数点问题,cdq 分治、树套树、分块套分块维护皆可。
显然这可以经典根号平衡。
我们可以序列分块套值域分块。序列分块要求单点修改,整体查询 \(nxt\) 值 \(<=r\) 的个数。显然可以再套一个值域分块,维护块内前缀和。因为单点修改 \(O(1)\),因此值域分块可以采用 \(O(\sqrt n) - O(1)\) 的方式,就可以平衡复杂度做到 \(O(n\sqrt n)\) 了。
LOJ 上过了,但是 luogu 机子慢。