数据结构选做 #2

数据结构选做 #2

Problem A. [ABC282Ex] Min + Sum

考虑对 \(A\) 建出笛卡尔树,枚举最小值。枚举较小的一边,二分另一边。每个位置最多枚举 \(O (\log n)\) 次,复杂度 \(O(n\log^2 n)\)

Problem B. CF2111G Divisible Subarrays

从小到大枚举 “分界点” \(x\),小于 \(x\) 的位置赋为 \(-1\),大于 \(x\) 的位置赋为 \(1\)。set 维护 \(-1,1\) 的连续段,每次变化 \(O(1)\) 个区间,变化时加入矩形,扫描线即可。

由于强制在线,修改在查询之前,所以可以上主席树。

https://codeforces.com/contest/2111/submission/334666350

Problem C. CF2128E2 Submedians (Hard Version)

先考虑 E1 咋做:二分 \(x\),判断是否有一个长度 \(\ge k\) 的区间有 \(\ge \lceil\frac {len} 2 \rceil\) 个大于等于 \(x\) 的元素,如果有说明中位数可以更大。

再考虑 E2:类似地,找出可能的最大、最小的中位数 \(v1,v2\) 及其区间 \([l1,r1],[l2,r2]\)。向一个区间里不断加入数,中位数的变化是连续的。类似莫队,令 \([l1,r1]\)\([l2,r2]\) 移动,移动过程中一定可以取遍 \([v1,v2]\) 所有数,边移动边统计答案即可。

https://codeforces.com/contest/2128/submission/334802771

Problem D. CF2096F Wonderful Impostors

一个陈述区间合法,当且仅当任意一个 1 区间不被 0 区间的并包含。

容易发现当 \(r\) 增大时,最小的 \(l\) 也会增大,所以双指针维护。

加入 1 区间时,不断增大 \(l\),直到 \([L,R]\) 不完全被 0 覆盖。线段树维护每个位置被覆盖次数。

加入 0 区间时,不断增大 \(l\),每次找到其所在的极长 0 段 \([L',R']\),直到 \([L',R']\) 内不包含 1 区间。设 \(p_i\) 为以 \(i\) 为左端点的 1 区间的右端点最小值,线段树+set 维护 \(p_i\) 区间最小值。

https://codeforces.com/contest/2096/submission/335279283

Problem E. CF2129E Induced Subgraph Queries

考虑莫队,每次可以 \(O(deg(x))\) 移动区间,第 \(k\) 小用 \(O(1)-O(\sqrt{n})\) 的值域分块维护。

但某个度数很大的点被更新很多次。于是我们按度数和划分莫队的块,度数 \(>B\) 的自成一块,其他点保证每块度数和 \(\le B\)。注意度数为 \(0\) 的点有 \(1\) 的贡献。视 \(n,m,q\) 同阶,总复杂度 \(O(n\sqrt{n})\)

https://codeforces.com/contest/2129/submission/335288468

Problem F. P11947 [KTSC 2025] 可爱区间 / maxsum

好题,值得一做。

套路地,首先考虑怎么判定 \([l,r]\) 合法。\([l,r]\) 内的元素一定全选 \(B\),外面的一定全选 \(A\)

然后讨论一下不合法的情况,设 \(S\)\(B\) 的前缀和,可以总结出条件:

  1. \([l,r]\) 内的 \(B\) 的最大子段和是本身,转化为对于 \(\forall i\in[l,r),S_{l-1}\le S_i\le S_r\)
  2. \([1,l),(r,n]\) 内的 \(A\) 的最大子段和小于 \(S_r-S_{l-1}\),转化为全局 \(A\) 的最大子段和 \(M\le S_r-S_{l-1}\)
  3. 最大子段和不包括 \(A\) 部分,设 \(g_i,h_i\) 为前/后缀 \(i\) 的最大子段和,转化为 \(g_{l-1}\le 0,h_{r+1}\le 0\)

第三个条件只和自身有关,重点考虑前两种。

拆一下限制,\(S_{l-1}\)\([l-1,r]\) 的最小值,建出单调栈后是栈里的一个元素。设 \(lim_i\)\(i\) 前面第一个大于 \(S_i\) 的位置,那么 \(l-1\ge lim_r\)。对于第三个条件,可以单调栈二分。所以对于 \(r\),合法的 \(l\) 是单调栈上的一段区间。

考虑扫描线,枚举 \(r\) 维护 \(l\)。每次先加上单调栈上区间贡献;然后弹栈,撤销,加入 \(r\)

对于询问,差分一下变成区间历史和,边扫边查即可。

https://www.luogu.com.cn/record/233152988

Problem G. UOJ228 基础数据结构练习题

若一个区间的数字全部相等,那么可以直接打区间减标记返回。

注意到 \(\sqrt{x}-\sqrt{y} \le \sqrt{x-y}\),于是一个区间最多被开 \(\log\log V\) 次。

记势能为 \(\sum \log \log (max_i-min_i)\)。区间开根时,区间内所有经过的节点势能减少 \(1\),两侧 \(O(\log n)\) 的个节点势能增加 \(1\)。区间加时,两侧 \(O(\log n)\) 的个节点势能增加 \(O(\log \log V)\)

势能分析最重要的检查:有没有使得势能无法减少的情况。由于下取整带来的误差,\(8,9,8,9,8,9\),开根后变为 \(2,3,2,3,2,3\),势能没有减小,但仍然可以直接打标记。所以若一个区间可以用区间减代替开根就返回。

总复杂度 \(O(n\log n\log\log V)\)

https://uoj.ac/submission/737649

Problem H. CF1942F Farmer John's Favorite Function

首先 \(\lfloor \sqrt{x} \rfloor=\lfloor \sqrt{\lfloor x\rfloor} \rfloor\),所以可以边做边取整。

但直接维护不好做,因为每次操作会影响很多位置。考虑离线后扫序列轴维护时间轴,瞬间明朗,转化为区间加区间开根。

Submission #335595994 - Codeforces

Problem I. CF2006E Iris's Full Binary Tree

如果树中有度数 \(>3\) 的点就死了。其余情况中,选择一个度数 \(<3\) 的点 \(x\) 作为根,答案为 \(\max(dis(i,x))\)

树中距离 \(x\) 最远的点一定是直径端点,所以加点时维护出直径的中点,dfn 序 + 线段树维护一下每个点到中点的距离即可。

Submission #335923861 - Codeforces

Problem J. P11191「KDOI-10」超级演出

对每个指令求出一个 \(pre_i\),表示至少需要执行 \([pre_i,i]\) 中的指令才能让 \(a_i\) 退场。然后扫描线即可。

但是求一个 \(pre_i\) 需要 \(O(deg_{a_i})\) 的复杂度。对度数根号分治,设一个阈值 \(B\),度数 \(\le B\) 的点暴力求,每个点求完之后更新一下 \(>B\) 的点,视 \(n,m\) 同阶,复杂度 \(O(nB+\frac {n^2}B)\),取 \(B=\sqrt{n}\) 即可。

https://www.luogu.com.cn/record/233966847

Problem K. P10846 [EGOI 2024] Team Coding / 团队编程

枚举领导 \(x\),枚举深度 \(d\),答案为 \(\sum \min(capacity_{x,d},tot_{a_x,d})\)\(capacity_{x,d}\) 表示 \(x\) 子树内深度为 \(d\) 的点的个数,\(tot_{c,d}\) 表示整棵树颜色为 \(c\) 且深度为 \(d\) 的点个数。直接做是 \(O(n\times dep)\) 的。

考虑根号分治,若颜色 \(c\) 的个数 \(\le B\),那么只枚举有 \(c\) 的深度。若颜色 \(a_x\) 的个数 \(>B\),一个点的祖先中如果有颜色相同的一定不优,所以只枚举合法点的子树。复杂度 \(O(nB+\frac{n^2} B)\),取 \(B=\sqrt{n}\) 即可。

https://www.luogu.com.cn/record/234217256

posted @ 2025-08-21 22:06  XP3301_Pipi  阅读(23)  评论(0)    收藏  举报
Title