2023下半年部分做题记录

前言

中考考完了呢,看看现在搞 OI 能搞出什么花头来吧。

23/08/02

二维数点板子。
考虑离线询问,将一个询问拆成若干个 \((0, 0, x, y)\) 的询问的容斥,然后就是计算 \(x_i\leqslant x\land y_i\leqslant y\) 的点的个数。经典二维偏序,做法一万种,但我喜欢树状数组。

神仙换根dp题。
假设一开始的树中只有一个点,令其为 \(rt\)
那么每次新加一个点的时候,必然是如此:

  • 新建一条红边:将新的点 \(v\) 与原来和 \(rt\) 在一个连通块里的 \(u\) 连边。不难发现 \(dep_v>dep_u\)
  • 新建两条蓝边:选一条红边 \(<u,v>(dep_v>dep_u)\),新建点 \(p\),不难发现 \(dep_v>dep_p>dep_u\)

不难发现对于一组蓝边 \(<u,p>\)\(<p,v>\),其必然有 \(fa_v=p,fa_p=u\)。呈现在树上就是两条连续的父子边。
定义一个点是中间点当且仅当该点存在于一组蓝边且该点为上述的 \(p\)
则我们可以设计 dp 状态。
\(f_{u,0/1}\) 表示目前考虑以 \(u\) 为根的子树,\(u\) 是否是中间点。
则考虑一下转移。
为了方便,令 \(calc(u,w)=f_{u,0}+w-\max(f_{u,0}, f_{u,1}+w)\)

\[f_{u,0}=\sum_{v\in Son(u)}\max(f_{v,0}, f_{v,1}+w_{u,v})\\ f_{u,1}=\max\limits_{v\in Son(u)}(f_{v,0}+w_{u,v}+\sum_{v'\in Son(u)\land v'\neq v}\max(f_{v',0}, f_{v',1}+w_{u,v'}))=f_{u,0}+\max\limits_{v\in Son(u)}(calc(v,w_{u,v})) \]

原因显然。
\(f_{u,1}\) 中使其取到最大值的 \(v\)\(calc(v,w_{u,v})\)\(mx_u\),次大值为 \(mxx_u\)。(用于换根)
这样在确定 \(rt\) 的情况下,\(f_{rt,0}\) 便是答案。
但是我们怎么知道哪个是 \(rt\) 呢?
不如全部取一遍,贪最大值,最大的就是 \(rt\)
那么我们就需要换根 dp 了。
先取一个你喜欢的点为根,然后换根。下文的 \(fa,Son\) 都是相对换根之前的树而言。
\(g_{u,v,0/1}\) 表示对于一条树边 \(<u,v>(fa_v=u)\),当 \(v\) 是整棵树的根时 \(u\) 子树的贡献。
考虑从 \(g_{fa_u,u,0/1}\) 推到 \(g_{u,v,0/1}\)
分类讨论。
\(mx_u>calc(v,w_{u,v})\) 时,去除 \(v\) 子树并不影响取 \(\max\),则有

\[g_{u,0}=f_{u,0} - \max (f_{v,0}, f_{v,1}+w_{u,v}) + \max (g_{fa_u,0}, g_{fa_u,1}+w_{fa_u,u})\\ g_{u,1}=g_{u,0} + \max (mx_u,calc(fa_u,w_{fa_u,u})) \]

\(mx_u=calc(v,w_{u,v})\) 时,去除 \(v\) 子树影响了取 \(\max\),因此我们要修改一下 \(g_{u,1}\) 的递推式

\[g_{u,1}=g_{u,0} + \max (mxx_u,calc(fa_u,w_{fa_u,u})) \]

不难发现,以 \(u\) 为根的答案即为

\[f_{u,0}+\max(g_{fa_u,0},g_{fa_u,1}+w_{fa_u,u}) \]

于是这道题就做完了。

23/08/03

萌萌题。
设上一个与 \(i\) 同色的点为 \(pre_i\),其权值 \(p_i=i-pre_i\),则 \(ans(l,r)=\sum\limits_{i\in[l,r]\land pre_i\geqslant l}p_i\)
这样不是很好操作,但是不难发现,若将序列中的下标 \(i\) 抽象成平面中的点 \((i,pre_i)\),权值为 \(p_i\),则答案即为 \((l,l)\) 为左下角,\((r,n)\) 为右上角的矩形覆盖点权和。
又由于不存在点满足 \(y>x\),则答案矩形为 \((1,l)\) 为左下角,\((r,n)\) 为右上角的矩形。这只需要一个 cdq 就能完成。
现在有了单点修改。
设下一个与 \(i\) 同色的点为 \(nxt_i\),若现在要改变 \(i\) 的颜色,则哪些点需要添加/删除?

  • 删除 \((i,pre_i)\)
  • 删除 \((nxt_i,i)\), 添加 \((nxt_i,pre_i)\)

设将 \(i\) 变色后上一个同色点为 \(pre'_i\),下一个同色点为 \(nxt'_i\)

  • 删除 \((nxt'_i,pre'_i)\)
  • 添加 \((nxt'_i,i)\), 添加 \((i,pre'_i)\)

维护每个颜色的点用 set 即可。
发现删除一个点这个操作不好处理,我们可以不把它删除,而是添加一个与其相同的点,将权值取负,以达到正负抵消的效果。
之后以时间为第一维,平面为第二、三维 cdq 分治即可。

23/08/07

最大子段和乱搞题。
对于常规的题目,建一棵线段树维护 lmx, rmx, mx, sum 便可轻松解决。
但是这道题要求左右端点有范围。
考虑分类讨论,用常规信息能维护出来的信息加一点点贪心推出答案。
设左端点 \(l\in [ll, lr]\),右端点 \(r\in [rl, rr]\)

  • \(lr < rl\)
    此时左端点的范围与右端点的范围不交,不难发现中间的那部分必须取,然后两边分别取最大前后缀就好了,最后加起来。
    由于题目要求不能取空段,则 \(ans=sum_{[lr,rl]}+rmx_{[ll,lr]}-a_{lr}+lmx_{[rl,rr]}-a_{rl}\)

  • \(lr \geqslant rl\)
    此时左端点的范围与右端点的范围有交 \([rl,lr]\),考虑答案会以什么样的形式出现,再次分类讨论。

    • \(l,r\in[rl,lr]\),此时变成了板题,\(ans=mx_{[rl,lr]}\)
    • \(l\in[ll,rl],r\in[rl,lr]\),则以 \(rl\) 为分界线向左右两边分别取最大前后缀,最后加起来,\(ans=rmx_{[ll,rl]}+lmx_{[rl,lr]}-a_{rl}\)
    • \(l\in[rl,lr],r\in[lr,rr]\),与上面的情况类似。
    • \(l\in[ll,rl],r\in[lr,rr]\),不难发现 \(ans=rmx_{[ll,rl]}+sum_{[rl,lr]}-a_{rl}+lmx_{[lr,rr]}-a_{lr}\)

    四种情况取最大值即可。

然后你就做完了。

23/08/08

萌萌题。
手玩样例可以发现对于一个区间 \([l,r]\),其众数只可能是 \(1\) 或者 \(b_l\),证明不难。
又可以发现,若 \(b_l\in a_L, b_r\in a_R\),当且仅当 \(\forall i \in [L,R), a_i\geqslant b_l\),则该区间的众数为 \(b_l\)
考虑固定 \(l\),求有多少个 \(r\) 满足条件。不满足条件的区间其众数均为 \(1\)
我们在平面直角坐标系上画一个方格图,格子 \((i,j)\) 被染色当且仅当 \(j\in[1,a_i]\),不难发现格子上每一个数和 \(b_i\) 一一对应。设 \(b_l\) 对应的格子是 \((x,y)\),则满足条件的格子 \((x',y')\) 应有如下限制:

  • \(x' \geqslant x\)
  • \(y' \geqslant y\)
  • \(\forall i \in [x,x'], a_i\geqslant y\)

也就是 \((x,y)\) 右上角的连通块。
如何维护连通块呢,考虑到连通块的右边界一定是一个极小值,因此单调栈从右往左维护单调递增的序列 \(a\) 即可。
于是我们有了一个初步的算法,从右往左枚举每一个格子 \(O(\sum a)\),对于每个格子使用单调栈计算其贡献。
为了方便,我们先在栈中压入 \(n+1\)\(a_{n+1}=0\)
对于格子 \((x,y)\),其能对答案产生贡献的格子数量为:若 \(y\in (a_{sk_{I-1}},a_{sk_I}]\),设 \(a\) 的前缀和为 \(s\),则 \(cnt=(s_x-s_{sk_{I-1}})-(x-sk_{I-1})\times(y-1)\),贡献为 \(cnt\times y\)。画个图就清晰了。
最后用总区间数减去我们统计过的产生贡献的区间数便是剩下的 \(1\) 的区间数。
我们发现这个式子中与 \(y\) 有关的只有 \(y-1\) 这一项,不难发现对于所有的 \(y\in(a_{sk_{I-1}},a_{sk_I}]\),其贡献可以合并。化简式子过程略。
式子化完之后就不含 \(y\) 了,我们可以将这两个关于 \(x\) 的式子前面的系数单独拿出来。不难发现,这些系数都有一个特点,它们的值只与栈的形态有关。因此我们可以将其在栈的形态发生变化时算出来,那么这个式子就是 \(O(1)\) 的了。
式子太长了,就不放了。
但是这确实是一道好题,有一万种做法,却卡了我场上的大常数线段树。

23/10/02

做完这道题感觉又学会了一类信息的维护呢。
先离线询问,按右端点 \(r\) 升序排序,问题转化为一开始两个空序列,不断从左到右依次加元素,在任意时刻询问一段后缀的答案。
令当前序列的长度为 \(r\),若我们需要知道 \([l,r]\) 的答案,由于 \(ans=\sum\limits_{[p,q]\subseteq[l,r]}\left(\max\limits_{i\in[p,q]}a_i\right)\left(\max\limits_{i\in[p,q]}b_i\right)\),考虑令 \(f_l\) 表示枚举 \([p,q]\)\(p=l\) 的贡献,即 \(f_l=\sum\limits_{q=l}^r\left(\max\limits_{i\in[l,q]}a_i\right)\left(\max\limits_{i\in[l,q]}b_i\right)\),不难发现 \(ans=\sum\limits_{p=l}^rf_p\)
接下来考虑在添加一个新元素时如何更新 \(f\) 的值。
\(A_l=\max\limits_{i\in[l,r]}a_i\)\(B_l=\max\limits_{i\in[l,r]}b_i\),不难发现当 \(r\) 右移时, \(f_l\) 应当增加 \([l,r]\) 的贡献,而这部分贡献就是 \(\left(\max\limits_{i\in[l,r]}a_i\right)\left(\max\limits_{i\in[l,r]}b_i\right)=A_lB_l\)
于是我们可以在每次右移 \(r\)\(O(n)\) 更新 \(A_l\)\(B_l\) 然后再更新 \(f_l\),于是我们学会了 \(O(n^2+q)\) 的做法。
考虑如何继续优化。
不难发现,当右移 \(r\) 时,以 \(A\) 为例,如果有若干个 \(A_l\) 的值发生了变化,则这些 \(A_l=a_r\),因此变化的 \(A_l\) 一定是 \(A\) 的一个后缀,这可以用单调栈维护。\(B\) 同理。
于是我们需要一个数据结构支持以下三种修改操作以及区间求 \(f\) 的和:

  • 区间推平 \(A\)
  • 区间推平 \(B\)
  • 区间对 \(f\) 操作:\(f_i \leftarrow f_i + A_iB_i\)

考虑线段树上维护四个信息

  • \(\sum f_i\),也就是该区间内每一个 \(f\) 的总和,以下简记为 \(s_f\)
  • \(\sum A_i\),以下简记为 \(s_a\)
  • \(\sum B_i\),以下简记为 \(s_b\)
  • \(\sum A_iB_i\),以下简记为 \(s_{ab}\)

不难发现 \(\sum1=len\),无需动态维护。
对于前两种操作,我们可以在线段树上用两个标记 \(c_a,c_b\) 来完成推平。那在这种条件下如何维护 \(f\) 呢?
我们再引入四个标记 \(add_{ab},add_a,add_b,add_1\) 以表示 \(\sum A_iB_i,\sum A_i,\sum B_i,\sum1\) 的增量,这里 \(\sum\) 的范围均为线段树上该节点所维护的区间。很容易发现在下传标记的时候有 \(f\leftarrow f + add_{ab}\sum A_iB_i + add_a\sum A_i + add_b\sum B_i + add_1\sum 1\),那么标记的目的就达到了。(牢记这个式子,在下面下传标记时处理等价标记很重要)
我们在进行修改 \(A\) 时,只需要将目标区间的 \(c_a\leftarrow a_r\) 即可,修改 \(B\) 同理,修改 \(f\) 只需要 \(add_{ab} \leftarrow add_{ab} + 1\) 即可。
现在我们着眼于如何下传标记,只要这里处理好了这道题就做完了。
先定义所有 \(add\) 的优先级高于 \(c\),即先下传 \(add\) 再下传 \(c\),同时 \(fa_{add}\) 是直接作用于 \(ch_c\) 上的。
\(fa\) 下传到 \(ch\) 时,先将 \(add\) 下传到等价标记,由于有区间推平的干扰,我们分四类情况讨论:

  • \(ch_{c_a}\)\(ch_{c_b}\) 均存在
    此时等价于直接把贡献全都扔到 \(\sum1\) 上,即

\[ch_{add_1} \leftarrow ch_{add_1} + ch_{c_a}ch_{c_b}fa_{add_{ab}}+ch_{c_a}fa_{add_a}+ch_{c_b}fa_{add_b}+fa_{add_1} \]

  • \(ch_{c_a}\) 存在
    此时由于 \(fa_{add_{ab}}\) 的贡献为 \(fa_{add_{ab}}\sum A_iB_i = fa_{add_{ab}}ch_{c_a}\sum b_i\),同时 \(fa_{add_a}\) 的贡献为 \(fa_{add_a}\sum a_i=fa_{add_a}ch_{c_a}\sum1\),不难得出

\[ch_{add_b} \leftarrow ch_{add_b} + fa_{add_b} + fa_{add_{ab}}ch_{c_a}\\ ch_{add_1} \leftarrow ch_{add_1} + fa_{add_1} + fa_{add_a}ch_{c_a} \]

  • \(ch_{c_b}\) 存在
    与上面的情况类似,不难得出

\[ch_{add_a} \leftarrow ch_{add_a} + fa_{add_a} + fa_{add_{ab}}ch_{c_b}\\ ch_{add_1} \leftarrow ch_{add_1} + fa_{add_1} + fa_{add_b}ch_{c_b} \]

  • 都不存在
    此时直接无脑下传标记即可,即

\[ch_{add_{ab}}\leftarrow ch_{add_{ab}}+fa_{add_{ab}}\\ ch_{add_{a}}\leftarrow ch_{add_a}+fa_{add_a}\\ ch_{add_b}\leftarrow ch_{add_b}+fa_{add_b}\\ ch_{add_1}\leftarrow ch_{add_1}+fa_{add_1} \]

之后再将 \(c\) 下传,直接下传即可。
然后考虑下传标记对于节点维护信息的更新。
首先有 \(ch_{s_f}\leftarrow ch_{s_f}+fa_{add_{ab}}ch_{s_{ab}}+fa_{add_a}ch_{s_a}+fa_{add_b}ch_{s_b}+fa_{add_1}ch_{len}\)。对于剩下的三个信息,还是分四类情况讨论:

  • \(fa_{c_a}\)\(fa_{c_b}\) 都存在
    不难发现

\[ch_{s_{ab}}\leftarrow fa_{c_a}fa_{c_b}ch_{len}\\ ch_{s_a}\leftarrow fa_{c_a}ch_{len}\\ ch_{s_b}\leftarrow fa_{c_b}ch_{len} \]

  • \(fa_{c_a}\) 存在
    不难发现此时 \(ch_{s_b}\) 值未改变,并且

\[ch_{s_{ab}}\leftarrow fa_{c_a}ch_{s_b}\\ ch_{s_a}\leftarrow fa_{c_a}ch_{len} \]

  • \(fa_{c_b}\) 存在
    与上面的情况类似,此时 \(ch_{s_a}\) 值未改变,并且有

\[ch_{s_{ab}}\leftarrow fa_{c_b}ch_{s_a}\\ ch_{s_b}\leftarrow fa_{c_b}ch_{len} \]

  • 均不存在
    那真是太好了,什么都没变。(因为没有任何推平)

于是就做完啦!

23/10/31

一道令人眼前一亮的萌萌题。
首先考虑从左往右依次加入新区间时对答案的影响。一个比较典的贪心做法是设 \(f_i\) 表示当前序列中长度为 \(i\) 的严格上升子序列的结尾的最小值(\(f_0=-\inf\)),那么答案就是最大的 \(i\) 满足 \(f_i<\inf\)
我们考虑新加入一个区间 \([l,r]\)\(f\) 的影响。
\(f'\) 为更新过后的 \(f'\),我们不难发现以下转移:

  • \(\forall f_{j-1}<l,f'_j=\min(f_j,l)\)
  • \(\forall f_{j-1}\in[l,r),f'_j=\min(f_j,f_{j-1}+1)\)
  • \(\forall f_{j-1}\geqslant r,f'_j=f_j\)

复杂度 \(O(n^2)\)
考虑优化这个式子,不难发现任意时刻 \(f\) 是严格单调递增的,于是对于 \(f_{j-1}<l\) 的情况,不难发现只有当 \(f_{j-1}<l\land f_j\geqslant l\) 时需要特殊转移 \(f'_j=l\),否则直接 \(f'_j=f_j\) 即可。
再考虑 \(f_{j-1}\in[l,r)\) 的情况,不难发现这个操作类似于整段 \(f\) 区间 \(+1\) 后右移移位,其中最右边的一位溢出,最左边的空位正好是 \(f_{j-1}<l\land f_j\geqslant l\) 时的特殊转移 \(f'_j=l\)
于是可以直接上一棵平衡树维护,复杂度 \(O(n\log n)\)

posted @ 2023-08-02 14:20  luanyi1216  阅读(94)  评论(0)    收藏  举报