【题解】Solution Set - NOIP2024集训Day7 线段树分裂与合并、平衡树
【题解】Solution Set - NOIP2024集训Day7 线段树分裂与合并、平衡树
https://www.becoder.com.cn/contest/5449
「湖南集训」更为厉害
设 \(siz_x\) 为子树 \(x\) 的大小,\(sum_x\) 为子树 \(x\) 中节点的 \(siz_x-1\) 之和。
然后考虑线段树合并,把一棵子树上的信息存在一棵线段树上,下标是距离,但是线段树的信息不能平移啊。好的破产。
考虑按照 \(dep\) 建一棵主席树,然后查询 \(dfn[x]\sim dfn[x]+siz[x]-1\) 的就好了。
又去看了一下题解,线段树合并还是可以做的,下边不存相对距离,而存绝对距离,就是 \(dep\) 就好了。
「PKUWC2018」Minimax
首先所有权值都有可能被取到,所以式子的前两项都很好处理。
现在问题是算出每个权值分别概率就解决问题了。
先离散化一下。
考虑 dp。初始值 \(f_{i,j}=1\),\(i\) 为叶子节点,\(j\) 是她的权值。\(g(j)\) 表示在当前 \(i\) 的子树中,权值 \(j\) 对应的是 \(i\) 的那个儿子。
关键信息是一个节点至多有两个儿子。
现在就是要用 ds 去优化这个 dp。
直接线段树合并好了,为了规避掉代码中很烦人的判 \(x,y\) 的地方,我们直接分别把左右儿子当成 \(x\) 算一遍,再加起来(不合法的那一个 \(f\) 是 \(0\),最后对当前位置的贡献也是 \(0\)。
但是很难处理前后缀和的信息。
于是去请教了一下 cube,实际上的做法是:
在线段树合并的时候,维护后面括号那一坨,然后递归的单个节点的时候,打上乘法标记。
怎么维护后面那一坨?
我们在线段树上面维护区间和,每次合并左右儿子的时候,就计算左右儿子分别对对方的贡献。
因为我们是递归合并,所以必须有一个先后顺序,注意需要提前记录一下。
「POI2011 R2 Day2」旋转树木 Tree Rotations
每次相当于合并两棵子树,考虑在合并的时候计算这两个子区间的贡献,取交不交换的最大值就好了。
具体的,和上面 「PKUWC2018」Minimax 这道题很类似,每次合并的时候维护每个元素在另一棵树上比她大的有多少个,然后把总和加起来。
「TJOI / HEOI2016」排序
之前做过。
如果权值过大很难动态维护排序的过程,但是如果权值只有 \(0/1\),那就可以直接分前后连段线段树赋值就好了。
我们考虑二分答案,check
的时候将每个权值重新赋值为 \([a_i\ge mid]\),最后只需要看 \(q\) 这一位如果是 \(1\) 说明可以更大,否则更小。
总时间复杂度:\(O(n\log^2 n)\)。