record 1.2-1.5

YDRS#004 GLACIES

这个其实是 UNR#4 配对树。

你先考虑一个区间的贡献怎么算。我们直观感受一下大概就是你从下往上走,每次在这个点的子树内如果出现两个以上的点,就把它们随意合并(因为是 \(dep_u+dep_v-dep_{lca}\)),这个大概是可以证明的。

那回到原问题,很自然的想法就是考虑每个点作为 lca 会被计算几次,发现是它有数的子树个数除以 2 下取整,这个很麻烦。

看了 sol。

我们考虑把贡献拆到边上,一条边会被计算当且仅当两边都有奇数个点。这个方便维护多了。

你考虑对于一条边 \((u,v)\) 怎么算。把子树内的点在序列上改为 1,别的都是 0,然后做模 2 意义的前缀和,对下标分奇偶维护,你发现合法的方案数就是两个前缀和不同的方案数。这个加入的过程可以使用线段树维护。

然后你再考虑整个过程,轻重链剖分/dsu on tree 即可。

CF1916 E

给一棵树,每个点有颜色,定义 \(f(u,v)=diff(u,lca(u,v))diff(v,lca(u,v))\),其中 \(diff(u,v)\)\(u\rightarrow v\) 路径颜色数。求 \(f(u,v)\) 最大值。\(n\le 3\times10^5\)

我们肯定要在 lca 处统计答案,统计一个最大值一个次大值合并就行了。我们很希望这个答案有随着 lca 升高的某种单调性,但很不幸并没有,这意味着我们并不能提前排除一些一定不可能的方案,那就是说我们大概要同时维护所有点的答案。

那我们肯定要先考虑能不能增量构造。你比方说 lca 走了 \(u\rightarrow v\) 这条边,考虑谁的答案会发生变化。我们在到根的链上连出经典的 pre,那就是 \(pre=u\) 的子树加 1,\(pre=fa_u\) 的子树减 1。这个简单做。

呃呃,不知道哪里出问题了,拍了 300 组了。调不出来,再说。

CF1916 F

给一个点双连通图,和两个数 \(n_1,n_2\),要求把图划分成两个点集,大小要求如前,并且两个点集分别连通。\(n_1+n_2\le2000,m\le5000\)

我们在 dfs 树上考虑,尝试利用没有割点的性质。经过一些尝试之后,可能能给出一个解法,但是非常困难。

看了 sol。

我们考虑证明,对于任意一个当前合法的划分 \(V_1,V_2\),我们一定可以在 \(V_1\) 中找到一个不是割点,并且跟 \(V_2\) 连通的点。

首先一定有跟 \(V_2\) 连通的点是显然的。我们假设所有这样的点都是割点,然后找到一个最“边上”的割点,把它割掉之后,其中一个部分会没有割点,那么这个部分跟 \(V_2\) 不连通,说明这个被割掉的点是原图的割点,爆了。

所以每次找一个不是割点的点就行了。

zroi day3 C

我们先把原问题写成线性规划形式。

\[\begin{aligned} \text{maximize} &\sum_{i=1}^m b_i\\ b_i\le\sum_{j\in[l_i,r_i]} &a_j\\ \sum_{i=1}^n a_i&\le k\\ 0\le a_i,b_i&\le 1 \end{aligned} \]

虽然现在 \(a,b\) 可能是实数,但是由于所有的系数 \(\in\{-1,0,1\}\),这个叫 unimodular,似乎就可以证明一定在整数处取到最值。你感受一下二维的,交点确实只能在整点处,所以这个很有道理。

对偶一下。

\[\begin{aligned} \text{minimize}\ \lambda k+\sum &z_i+\sum w_i\\ w_i+p_i&\ge 1\\ \lambda+z_i\ge \sum_{j}[l_j&\le i\le r_j]p_j\\ \lambda,w_i,p_i,&z_i\ge 0 \end{aligned} \]

因为这个东西也是 unimodular 的,所以我们可以只关心整数解。

接下来开始人类智慧。首先注意到 \(w,p\) 的减小一定对答案有利,所以 \(w_i+p_i=1\),也就是说,对于每个区间,选择向 \(w\) 或者 \(p\) 贡献。

相当于是,选择一部分区间,它们被删去了,每个需要 1 点代价,另外一部分区间,让它们正常覆盖,比方说在 \(i\) 点覆盖 \(c_i\) 次,我们要求 \(\lambda+z_i\ge c_i\),也会有一些代价。

我们发现,\(z_i\) 完全没用:同样花费一点代价,我们可以直接把覆盖的区间删去。所以存在最优解,使得 \(z_i=0\)

现在,问题变成了,你可以选一些区间 \(S\),代价是 \(m-|S|+k\max c_i\),其中 \(c_i\)\(S\) 中区间覆盖之后的结果。

我们本来是要对每个 \(k\) 做这个东西,但是我们不妨转为枚举 \(c_i\) 的限制,然后求出最少不选多少个区间。这样对于每个 \(k\) 我们仍然可以凸包简单处理。

然后神秘的东西出现了:这个东西可以增量贪心。我不懂为什么,之后再学习。

然后可以线段树随便维护一下就做完了。

zroi A Fear

这个东西,我在场上,看了一道类似的冒泡的题,里面有个结论,你记 \(i\) 与它之前的位置构成的逆序对个数是 \(c_i\),每一轮冒泡会执行 \(c_i\leftarrow \max(0,c_{i+1})\)

你把查询拆成两个,然后我就考虑维护这个东西,反正经过有些复杂的思考,得出了一个有些复杂的做法,虽然它应该是 1 log 的,但是有非常巨大的常数,得到了预期分数。

上面这个确实可以做,核心思想就是你发现,每次是选这个区间里,最大的 \(k\) 个,然后剩下的那部分,是把 \(k\) 个数填到空着的位置里,有一部分数是不变的,然后做做做。

但是,看了 sol 之后,我发现,这个东西,等价于,在区间 \([l,\min(r,x+z)]\) 当中,最小的那几个。这个,非常,显然。

主席树,做完了。

Luogu P7125

第一个想法是按照 \(\frac{l'+r'}{2}\) 分类统计答案,考虑以这个位置为中心的所有区间,去计算哪些符合条件。

首先猜测这样的半径是一个区间,那显然是假了,但是我们发现一个性质:你把这个数的每次出现都拿出来,在这一次出现到下一次出现之间,这里有一个单调性,那我们就可以二分了,结合分块在线求区间众数出现次数的做法,我们可以做到低贱的 \(O(n\sqrt{n\log n})\),这是 lxl 题,所以过不了。

说起来,区间众数要做到严格 \(O(n\sqrt{n})\),并且线性空间的话,需要用 vector 存下来,然后对于散块里的每一个点,我们依次去 chk 它能不能让答案 +1,具体来说,我们在 vector 里找到它的下标,并且加 ans,看看那个数是不是在我们的询问区间里。

然后我不会做了,看了 sol。

我们考虑把这些询问离线下来,然后按照 \(cnt_x\) 根号分治,对于大的,我们暴力做就行了。对于小的,我们统一做,但是你要枚举这个出现次数的界 \(up\),然后通过双指针算出来每个位置最多能延伸到 \(p_x\),这样就可以 \(O(1)\) chk 了。

那现在我们手里有线性个 \((p,l,r)\),代表以 \(p\) 为中心,半径在 \([l,r]\) 内的区间是合法的。首先肯定差分一手,转化成 \((p,r,v)\),然后我们把条件列一列,发现这个是个二维数点,然后做一做就行了。

Luogu P4887

注意到值域只有 \(2^{14}\),考虑一种枚举异或后的数是谁的方案,\(\binom{14}{k}\)

我们考虑莫队的过程,每次相当于询问 \([l,r]\) 内跟 \(a_p\) 异或之后为 \(k\) 的有多少个。把这 \(m\sqrt{n}\) 个询问差分,离线下来,按照 \(r\) 排序,这相当于是 \(n\) 次单点修改,\(m\sqrt{n}\) 次询问,我们 \(O(\binom{14}{k})-O(1)\) 解决即可。

但是这是 lxl 题,他卡了空间,我们要尝试做到线性。

卡空间,无非就是把能在线处理的询问处理了,把一些询问压缩,多跑几次,每次只处理一部分,这几种方式。

我们发现,每次跑莫队已经是根号的了,所以我们只能跑常数次莫队,最后一种方法看起来不太合适。

我们考虑哪些询问是可以在线处理的。发现右端点移动时,它差分出来关于右端点的询问,是可以预处理的,这部分可以在线做。

我们考虑哪些询问时可以压缩的。发现右端点移动时,它差分出来的关于左端点的询问,是一个区间的形式,可以压缩。

这样,我们就把空间卡到了线性,可以通过。

ZJOI2017 树状数组

我们观察不到,可怜求的是一个后缀和。

所以我们进行另外的观察,观察一次修改之后,对每个位置进行询问,哪些位置能得到正确的结果,哪些位置是错误的。

我们发现,只有修改的那一个位置是正确的,别的位置是错误的。

所以我们现在只关心每个位置被修改了多少次。

考虑一次 2 操作 \([l,r]\),我们关心的是 \(l-1,r\) 位置被覆盖的次数模 2 是否相同。我们不妨把只覆盖 \(l-1\),只覆盖 \(r\),覆盖 \(l-1,r\) 的询问个数分别记作 \(a,b,c\),我们把 \(c\) 分成三类:给 \(l-1\),给 \(r\),谁都不给。然后大力列式子,发现不会算。

瞄了一眼 sol。

我们反过来,考虑修改对询问的影响,维护一个二维平面表示 \((l,r)\) 这个询问的答案,然后观察到一次修改操作对某一个 \((l,r)\) 不造成影响的概率如果是 \(p\),原来的答案如果是 \(q\),那么会有 \(q\leftarrow pq + (1-q)(1-p)\),这个东西显然可以用矩阵来表示。并且 \(p\) 的不同取值构成三个矩形。

那么我们现在要做的就是,维护一个平面,支持矩形乘,单点查。这个可以树套树,注意到操作顺序不会影响最终结果,标记永久化即可。

复杂度 2 log。

Ynoi2006 rprmq2

这个题,很困难。它要我们做矩形加,矩形最值,可以离线。我们第一个想法肯定是树套树,但是你发现这个标记不太好,所以不太行。

那我们考虑一些根号算法。比方说我们对操作进行分块,这样在每块中我们按照操作的位置把平面划分成 \(B^2\) 个块,我们只会对整块进行操作。

那么我们现在已经可以把复杂度从 \(O(mn^2)\) 优化到 \(O(mn)\)

看了 sol。

接下来,我们把要解决的问题稍微写得清楚一些。我们对每一块操作,首先要求出执行之前的所有操作之后,每一块的最值。接下来要在 \(B\times B\) 的平面上,执行矩形加和矩形最值。

前者,我们可以扫描线,然后做区间历史最值。后者,我们可以使用 kdt,或者,直接用 \(B\) 棵线段树也可以。

[十二省联考2019]春节十二响

这个题 spx 是不是之前跟我说过啊!

我们明显感觉,做法是贪心。考虑一个子树的答案怎么计算,根肯定单独分出来,各个子树我们分别找出最优解,然后把尾部对齐合并即可。

首先,如果我们证明了最优子结构,那我们合并肯定是这么合并的。接下来就是怎么证明最优子结构。

我们假设当前有一个不是最优解的子树,你考虑它第一个选择情况不一样的点,我们知道它肯定是原来没有被选现在被选了。你考虑把这个点跟它最优解里的那个合并起来,那这样里面会有一些点要弹出来对吧,但是弹出来的这些点

不会证 /ng。

好了看了 spx 的 blog 现在会证了。

你考虑我们现在操作的对象其实是一个可重集,表示这个子树里作为“开头”的数都是谁。

我们使用归纳法,假设我们的算法在当前位置 \(u\) 处产生解 \(S_u\),我们考虑任意的其它解 \(T_u\),我们想要证明 \(sum(S_u)\le sum(T_u)\)

我们现在手头有的,就是子树 \(sum(S_v)\le sum(T_v)\),以及 \(S_u=combine(S_{v_1},S_{v_2},\dots,S_{v_k},\{val_u\})\)

我们先来研究 \(combine\) 的性质。首先猜一个 \(sum(S_u)\le sum(T_u)\Rightarrow sum(combine(S_u,P))\le sum(combine(T_u,P))\)

然后你尝试证明,发现证不了。但是发现这个结论对于我们算法导出的解而言是成立的。

我们尝试证明,若 \(S_u\le T_u\),这里表示每一位上的偏序关系,那么 \(combine(S_u,P)\le combine(T_u,P)\),而这个是显然成立的,因为 \(S_i\le T_i\Rightarrow \max(S_i,P_i)\le \max(T_i,P_i)\)

我们把这个性质加入我们的归纳假设当中。你发现你可以证明 \(combine(S_{v_1},S_{v_2},\dots,S_{v_k})\le combine(T_{v_1},T_{v_2},\dots,T_{v_k})\),接下来考虑加入 \(val_u\)。简单分析之后发现仍然满足偏序关系。

这样,我们就证明了 \(combine(S_{v_1},S_{v_2},\dots,S_{v_k},\{val_u\})\le combine(T_{v_1},T_{v_2},\dots,T_{v_k},\{val_u\})\),也就是说 \(S_u\le T_u\),也就是说 \(sum(S_u)\le sum(T_u)\)

这个其实是一个归纳引入,我们使用更强的结论进行归纳。不过确实啊,这个取 \(\max\) 自然就应该满足偏序性质,我们应该先发现这个性质然后基于它去证明。

Luogu P7983

这个 \(b\) 很像一个前缀和函数对吧,我们想到了另外一道跟这个很像的题。但是你先别急,我们先想想,\(a\) 区间覆盖,查前缀和怎么做。

这个很简单,随便做到 \(O(\sqrt{n})-O(1)\)

我们再想下一个问题,如果没有 \(b\) 的修改怎么做。

之前那个题的做法可以用上了。我们对每个块存下来每个位置在这个里面出现了多少次 \(cnt_{i,p}\),然后修改的时候对整块改 \(sum_i\leftarrow sum_i+cnt_{i,p}\Delta\)。但是你发现这里修改是区间覆盖,所以我们可以记录出现次数的前缀和,然后直接修改 \(sum_i\leftarrow sum_i+(cnt_{i,r}-cnt_{i,l})\Delta\)

考虑这个 \(cnt\) 怎么算。你发现我们是前缀加,查询单点值。但是可以离线,扫一遍就行了。

那我们现在考虑加入对 \(b\) 的修改。我们考虑散块暴力重构,整块打标记,好像,做完了?

你别急,有点问题。我们重构的块个数是 \(O(m)\) 的,但是重构复杂度是 \(O(n)\)。爆爆爆。

你考虑做得好一点。你发现我们对于颜色改变的颜色段,去做 \(O(\sqrt{n})-O(1)\) 的修改,这样均摊下来修改次数是 \(O(1)\) 的。所以就做完了。

你别急,现在空间是 \(O(n\sqrt{n})\) 的,这肯定会炸。我们考虑一些常见的优化起不起作用。比方说离线对每一块分别算。大概想一下是可以这么做的,所以我们做完了。

posted @ 2024-01-08 06:55  PYD1  阅读(8)  评论(0)    收藏  举报