数据结构小记
只会做傻子题了。
CF576E
傻子题。线段树分治,对于每条边相邻的两次修改 \(t_1,t_2\),把 \([t_1+1,t_2-1]\) 时刻内这条边的颜色打到线段树上,维护 \(k\) 个可撤销扩展域并查集即可。
P4690
没那么傻的题。如果是单点赋值的话就是动态二维数点,CDQ 分治直接做就行了。然后发现区间赋值只会产生 \(\mathcal{O}(n+m)\) 个 \(pre\) 的修改,然后就做完了。ODT 维护颜色段,再对每种颜色维护所有段就可以维护 \(pre\) 了。
P5631
傻子题。把所有边权为 \(x\) 的边扔掉就可以 \(\mathcal{O}(n\alpha(n))\) check。考虑分治优化,分治到 \([l,r]\) 时保证 \([1,l-1]\) 的边都加了。然后把 \([mid+1,r]\) 的边全部加进来,连通答案就是 \(l\),否则递归解决,可撤销并查集随便维护。
P1527
入门题。整体二分,用二维 BIT 维护。
P3769
四维 LIS。先按 \(a\) 排序,CDQ 分治,两边按 \(b\) 排序,双指针一下转成动态二维偏序,再套一个 CDQ 分治就行了。
P3527
入门题。整体二分,树状数组维护。
P3733
傻子题。根据经典结论,要用线性基维护所有非树边对应环的异或和。线段树分治,可撤销并查集随便维护,线性基也是很好撤销的。
P4175
入门题。整体二分,树状数组维护 DFS 序。
CF1140F
入门题。建二分图,对于一个连通块,如果里面有 \(x\) 个左部点,\(y\) 个右部点,那就有 \(xy\) 的贡献。线段树分治维护。
P3309
经典题。线段树维护凸壳,尾插时只重构那些恰好以该点为右端点的区间。
CF710F
入门题。二进制分组暴力合并 AC 自动机。
P3810
板子。CDQ 分治,树状数组维护。
QOJ3684
把条件转化成 \(x^2+y^2\leq \min\{2a_ix+2b_iy\}\),CDQ 分治后建出凸包维护。卡精度,傻逼。
P2617
入门题。整体二分,树状数组维护。
P5787
板子。线段树分治,可撤销扩展域并查集维护。
UOJ191
有点牛的题。尾删使得 P3309 的做法会死。考虑一种比较高妙的重构方法,在尾插时,对于每个恰好以 \(x\) 为右端点的节点 \([l,r]\),考察 \([l,r]\) 在当前层中的前一个节点 \([l',r']\),若其需要被重构则执行重构。叶子需要特殊处理。这样一个节点被重构后,至少要 \(\mathcal{O}(len)\) 次操作才会再次重构,所以均摊下来复杂度是整体 \(\mathcal{O}(n\log{n})\) 的。查询时依旧会拆成 \(\mathcal{O}(\log{n})\) 个区间,所以询问复杂度还是双 \(\log\) 的。卡细节、卡空间,傻逼。
P6240
入门题。猫树分治维护背包。
SPOJ9576
傻子题。线段树分治,可撤销并查集维护。
P14368
难难难。\(q=1\) 时有 \(\mathcal{O}(n\log{n})\) 的分治做法。考虑倍增值域分块,块内的两个端点 \(l,r\) 满足 \(2^i\leq l\leq r<2^{i+1}\),即 \(2l>r\)。此时对于一个包含 \(x\) 的合法区间,左右端点中至少有一个到 \(x\) 的距离 \(\leq l\)。这样假如枚举左端点 \(L\) 满足 \(x-l+1\leq L\leq x\),那么所有以 \(L\) 为左端点的合法区间都可以贡献到 \(x\) 上,可以直接预处理出 \(f_L=\max\limits_{L+l-1\leq i\leq L+r-1}\{s_i-s_{L-1}\}\),然后单调队列算滑动窗口最大值。右端点同理。于是我们可以 \(\mathcal{O}(n)\) 解决 \(2l>r\) 的 case。对每个整块预处理答案,建出 ST 表,询问时散块直接线性做,复杂度就是 \(\mathcal{O}(n\log{n}\log\log{n})-\mathcal{O}(n)\)。
CF678F
傻子题。线段树分治,可撤销李超线段树维护。
P5445
有点牛。考虑一个 \(0/1\) 矩阵 \(A\),其中 \(A_{i,j}\) 表示当前 \(i,j\) 是否连通。用 set 维护一下 \(0\) 的位置,可以发现每次修改相当于给矩形赋值 \(0/1\)。考虑怎么处理前缀时刻的答案,贡献提前计算,把 \([t+1,q]\) 时刻的 \(0/1\) 贡献视为当前状态,操作变成矩形加或减 \(q-t\)。询问时若 \(i,j\) 连通则把 \(q-t\) 扣掉即可。CDQ 分治简单维护。
P4246
和 SPOJ9576 没区别。
LOJ121
和 SPOJ9576 没区别。
CF1045G
傻子题。按 \(r\) 从小到大排序后只需要保证左边的能看到右边的。CDQ 分治,那就变成了二维数点。可以实现的优雅一点,两边按 \(q\) 排序,双指针,树状数组维护所有合法的 \(x\)。
P4390
入门题。CDQ 分治,树状数组维护。
P4849
和 P3769 一样。
CF938G
和 P3733 一样。
P4169
入门题。CDQ 分治,分讨拆绝对值,树状数组维护。
Gym102354B
不难。调和一下,只用考虑怎么求出 \(c_1\)。\(\max\) 不好维护,考虑二分答案转成求和,也就是转化成求
莫反变成
把所有 \(a_{id},b_{id}\) 排序,那么后面的两个 \(\sum\) 可以直接双指针求出。这样整体时间复杂度为 \(\mathcal{O}(n\ln^2n\log{V}\log{n})\),无法承受。
考虑优化排序的部分。可以发现最外层枚举 \(k\) 时,内部相当于给 \(d\) 乘了个 \(k\)。完全可以提前 \(\mathcal{O}(n\ln{n}\log{n})\) 求出对于所有 \(d\),\(a_{id},b_{id}\) 排序后的结果,时间复杂度降至 \(\mathcal{O}(n\ln^2n\log{V})\),可以通过。
CF848C
傻子题。拆成 \(i-pre_i\) 之和,动态二维数点,CDQ 分治维护。
P8569
神题。
容易得到一个 \(\mathcal{O}(n\log{V})\) 的做法。拆位,对于某一个位 \(i\),一个区间在该位上有贡献当且仅当其中存在 \(1\)。考虑从小到大右端点 \(i\),设 \(f_{j}\) 为 \(a_{1\sim i}\) 在第 \(j\) 位中最后一个 \(1\) 的位置。每次加入一个 \(a_i\) 时,若 \(\operatorname{bit}_j(a_i)=1\),则令 \(f_j\gets i\),否则不变。每个 \(i\) 会对答案贡献 \(2^i\sum\limits_{j=0}^{\log{V}}f_j\)。
考虑优化。这里使用一个很牛的 trick:注意到我们的转移在维护 \(f\) 时相当于维护了 \(\log{V}\) 个 \(\leq n\) 的数,考虑把 \(f\) 视作一个 \(\log{V}\times \log{n}\) 的 \(0/1\) 矩阵,那么我们将这个矩阵转置,改为维护 \(\log{n}\) 个 word。
考虑原来 \(f\) 的变化怎么放到 \(g\) 上。考察一个位 \(j\) 使得 \(\operatorname{bit}_j(a_i)=1\),对于每个 \(k\),我们需要把 \(g_k\) 的第 \(j\) 位设为 \(\operatorname{bit}_j(i)\)。不难看出这相当于:枚举 \(k\),若 \(\operatorname{bit}_k(i)=1\),则令 \(g_k\gets g_k\operatorname{or} a_i\),否则令 \(g_k\gets g_k\operatorname{and} \lnot a_i\)。此时每个 \(i\) 对答案贡献 \(\sum\limits_{j=0}^{\log{n}}2^jg_j\)。
P5416
击杀了,感觉不到黑。
套路地建出版本树,放到 DFS 序上考虑,显然所有点的出现区间会在 DFS 序上形成最多 \(n\) 个连续区间,DFS 的时候简单维护即可找出。
拆一下询问的式子,变成 \(x_0^2+\min\limits_{(x,c)\in S_p}\{-2x\cdot x_0+(x^2+c)\}\)。显然可以把每个点视作一条 \(k=-2x,b=x^2+c\) 的直线,对点集内的直线建出上凸壳即可查询出 \(\min\)。
考虑线段树,在每个节点上维护一个 vector,每个区间会在线段树上分成 \(\mathcal{O}(\log{n})\) 个节点,把 \(id\) 插进这些节点对应的 vector 里。然后对于线段树的每个节点,把这个节点的 vector 对应的直线排序后单调栈建出上凸壳,查询时对每个经过的节点都二分一下。这样复杂度是 \(\mathcal{O}((n+m)\log^2{n})\) 的。
显然可以优化。我们提前把 \(\mathcal{O}(n)\) 个区间按照对应直线的斜率排序,这样所有插入操作完成后,每个 vector 里的对应直线就已经排好序了。询问可以同理按照 \(x_0\) 排序,把二分改成暴力走指针。这样两边复杂度都降至 \(\mathcal{O}(n\log{n})\) 了。
CF232E
直接 bitset 跑可达性是 \(\mathcal{O}(\frac{n^4}{\omega}+q)\) 的,无法承受。显然这样完全没有利用网格图的性质,考虑对 \(x\) 坐标猫树分治,每次只需处理出 \(f_{i,j,k}\) 表示能否从 \((i,j)\) 走到 \((mid,k)\),\(g_{i,j,k}\) 表示能否从 \((mid,k)\) 走到 \((i,j)\)。询问时只需要判断 \(f_{x_1,y_1}\) 与 \(g_{x_2,y_2}\) 是否有交集。时间复杂度降至 \(\mathcal{O}(\frac{n^3\log{n}}{\omega}+\frac{qn}{\omega})\)。
P4027
简单题。令 \(f_i\) 表示前 \(i\) 天最多能持有多少人民币,\(x_i,y_i\) 表示在第 \(i\) 天用 \(f_i\) 元分别能兑换多少 A 券和 B 券。解方程可得 \(x_i=\dfrac{f_ir_i}{a_ir_i+b_i},y_i=\dfrac{f_i}{a_ir_i+b_i}\)。那么转移就是 \(f_i\gets \max(f_{i-1},\max\limits_{1\leq j<i}\{a_ix_j+b_iy_j\})\)。用 P3309 中的方法维护即可。

浙公网安备 33010602011771号