数据结构做题笔记
LG2827 [NOIP2016 提高组] 蚯蚓
用单调队列简单维护就可以做到 $O(m\log m) $,但 \(m\) 有点大,我们就需要考虑特殊性质。
注意到每次切割的蚯蚓长度一定小于前几次切割的长度(指的是没有每天增加 \(q\) 的情况下)。
这样考虑使用队列 \(q[3]\) 分别维护还没有切割的,切割后左边的,切割后右边的即可。
时间复杂度 \(O(m)\)。
另外读入的数组并不是单调的,但是给出的样例却都是单调的。
LG5268 一个简单的询问
区间询问,\(10^5\) 级,想到莫队。
但每个询问拥有两个约束条件,不能直接处理。
设 \(p_{l,x}\) 表示 \(1\sim l\) 中 \(x\) 的出现次数。
将 \(q\) 个询问拆成 \(4q\) 个子问题,就可以使用莫队统一求解。
LG3045 Cow Coupons G
想到一个结论——
\(c\) 值前 \(k\) 小的奶牛一定会被购买。
考虑反证法。
如果 \(c\) 值前 \(k\) 小的奶牛为被购买,那么就一定可以将其中的奶牛代替现在使用优惠的奶牛,方案更优。
但是, \(c\) 值前 \(k\) 小的奶牛并不一定会使用优惠券。
假设已经购买的奶牛中使用优惠的一头奶牛为 \(x\) ,未使用优惠的奶牛为 \(y\),那么当且仅当 \(p_x-c_x<p_y-c_y\) 时,将 \(x\) 的优惠给 \(y\) 使用会使得整体方案更优。于是如果出现了上述情况, \(c\) 值前 \(k\) 小的奶牛可以考虑不使用优惠使得整体方案更优。
考虑先将 \(c\) 值前 \(k\) 小的奶牛加入购买方案,全部使用优惠券,再考虑其它的奶牛。
对于一头奶牛 \(i\) 有两种方案,一种是直接购买,花费 \(p_i\), ,另一种是取代奶牛 \(j\) 的优惠券,花费为 \(p_j-c_j+c_i\) 。
使用三个优先队列分别维护 \(p_i,c_i,p_j-c_j\) 的最小值。
LG3586 LOG
思考询问操作如何处理。
发现如果任何一个节点如果大于 \(s\) 的话,最多发挥 \(s\) 的价值。
因此我们只需要找到大于等于 \(s\) 的数的个数,还有小于 \(s\) 的价值的和就可以得出能否进行 \(s\) 次操作。
相当于需要一个支持找到数的排名,全局第 \(k\) 小,查询区间和还有单点修改的数据结构,用平衡树维护。
LG4514 上帝造题的七分钟
使用差分和前缀和进行维护数值。
设差分数组为 \(s_{a,b}\),每次区间修改就使 \(s_{a,b},s_{c+1,d+1}\) 加一,\(s_{c+1,b},s_{a,d+1}\) 减一,使用树状数组维护前缀和即可求出单点的数值。
现在问题转到区间的求和。
使用二维树状数组维护 \(s_{k,s},ss_{k,s},ks_{k,s},kss_{k,s}\) 。
LG3960 列队
容易想到将 \(n\times m\) 的矩阵分为 \(n+1\) 个数列用平衡树维护。
前 \(n\) 棵为 \(n\) 行的前 \(m-1\) 个元素。
最后一棵平衡树维护 第 \(m\) 列的 \(n\) 个元素。
注意到 \(n,m\leq3\times 10^5\),用平衡树直接维护空间显然会炸掉。
然而操作数 \(q\) 也是 \(10^5\) 量级,所以我们想到可以用一个节点维护一个区间范围内的数,当这个区间 \([l,r]\) 内的 \(x\) 位置的数需要删除的时候将这个区间删除,并插入 \([l,x-1]\) 和 \([x+1,r]\) ,这样就可以减少空间复杂度。
注意到一个问题,我们需要一个关键字排序需要保证区间有序。分裂的区间是可以直接插入的,但是从第 \(m\) 列插入的数还需要保证有序。于是我们将从后面插入的数 加上 \(x\times nm\),\(x\) 随着插入逐渐增加,做好标记。读取的时候再减去就好了。
LG3302 森林
如果只有询问操作,就直接在树上构建主席树,在主席树上二分就可以了。
但是还有连边操作,考虑启发式合并,每次连边将节点数较小的树接到节点数较大的树上,暴力重构节点数较小的那部分的主席树即可。
LG3293 美味
看到异或值最大,想到类似于 01-trie 的做法。
询问区间信息,又是与权值有关,自然想到主席树。
从高到低枚举,设前面已经找到的最大的权值为 \(pre\)(还没有枚举到的数默认填 0)。
我们假设第 \(i\) 位需要 1,只要在主席树上查询 \([pre+2^{i-1},pre+2^i )\) 这个区间有没有数,没有的话这一位只能填 0。
需要 0 的情况也是一样。
LG3644 八邻旁之桥
若 \(k=1\), 中位数就是答案。
若 \(k \leq 2\),考虑可以将整个河岸分成两个部分,于是从前往后,从后往前分别跑一次求动态中位数。
用对顶堆,平衡树或者权值线段树都可以维护。
LG3380 二逼平衡树
树套树板子。
区间线段树套平衡树,相当于对每个线段树的节点都建立一棵平衡树,空间复杂度 \(O(nlogn)\)。
查询区间排名就只需要在属于该区间的 \(O(logn)\) 个线段树节点中的平衡树分别查询。
查询区间第 \(k\) 小,在查询区间排名的基础上二分,时间复杂度 \(O(nlog^3n)\)。
修改就在包含该节点的 \(O(logn)\) 个线段树节点的平衡树中分别修改。
LG2617 Dynamic Rankings
树状数组套权值线段树(其实上面那题也可以用的,不仅时间复杂度更优,而且好写)。
修改同一般的树状数组,只是每个节点要在主席树上修改。
查询将 \(O(logn)\) 个节点拿出来,在这几棵主席树上同时二分。
LG3332 K大数查询
其实一开始写的是区间线段树套权值线段树的,结果发现空间爆炸,只有 20 分。因为这题是区间加。
所以需要权值线段树套区间线段树,直接在权值线段树上二分。
LG3759 不勤劳的图书管理员
鉴于出题人语文可能不太好,需要翻译一下题面。
给定 \(a_i,v_i,求 \Sigma_i\Sigma_{j<i}[a_i<a_j](v_i+v_j)\),带修改(指两点交换)。
树状数组套权值线段树可以求出一个位置的数和其前缀的答案。
修改就在这个基础上做一些加加减减。
LG3242 接水果
树上的区间包含问题,考虑用 dfs 序转化。
设 \(L_x\) 表示 \(x\) 的 dfs 序,\(R_x\) 表示以 \(x\) 为根的子树内的 dfs 序的最大值,即 \(R_x=L_x+size_x-1\)
设水果为 \([x,y]\),那么盘子 \([u,v]\) 要想被水果包含,就有两种情况。
不妨设 \(depth_u<depth_v\)
- \(lca_{u,v}=u\),设 \(z\) 为 \(u\rightarrow v\) 上第一个节点。
需要满足\(L_x\in[1,L_z-1]\cap [R_z+1,n],L_y\in[L_u,R_u]\) - \(lca_{u,v}\neq u\),
需要满足 \(L_x\in[L_u,R_u],R_x\in[L_v,R_v]\)
不妨将这两个节点看作一个二维空间上的坐标,要求的区间信息则可以看成是一个矩形。按 \(x\) 坐标排序,类比扫描线的思路维护 \(y\) 轴上的信息。现在我们需要一个支持区间插入,查询单点第 \(k\) 小的数据结构,用权值线段树套区间线段树维护。

浙公网安备 33010602011771号