ds 训练

部分题意来自 洛谷 的中文翻译。

CF526E

题意:给你一个环形数组,让你求将这个数组分成 每段和 \(\le k\) 的最小段数。
\(n\le 10^5\)\(q\le 50\)

显然是 \(O(nq)\)
考虑对于极大的段 \([l,r]\) 只有所有的 \(r+1\) 才有可能是答案的起点。
从随意一个点开始走转两圈记录上一次是第几段即可。

https://codeforces.com/contest/526/submission/241939207

CF997E

求一个给定排列中连续子区间的数量。
\(n,q\le 10^5\)

考虑一个连续的子区间 \([l,r]\) 满足 \(\max-\min-r+l=0\),同时我们发现这是可能的最小值。
所以只需要维护最小值以及最小值计数即可。
考虑区间查询,发现可以和 NOIP 2022 比赛 一样做。
把询问离线下来,移动右端点,维护后缀最小值计数及其历史和。
注意 long long
\(O(n\log n)\),默认 \(n,q\) 同阶。

https://codeforces.com/contest/997/submission/242417197

CF464E

给定一张 \(n\) 个点,\(m\) 条边的无向图,每条边的边权为 \(2^{x_i}\),求 \(s\)\(t\) 的最短路,结果对 \(10^9+7\) 取模。
\(n, m, x_i \leq 10^5\)

考虑到每次只加一位,那么修改的信息不多,考虑二进制下的位数构成的序列,可以直接用主席树维护。每次加就先线段树上二分出 \(1\) 的一段,改成 \(0\),然后再把 \(0\) 改成 \(1\)
比大小用哈希判断高位,是否相等,也是线段树上二分出第一个不一样的。
有了这小操作就可以直接跑 Dijkstra 了。
\(O(m\log ^2n)\)

https://codeforces.com/contest/464/submission/242497401

CF603E

给定一张 \(n\) 个点的无向图,初始没有边。
依次加入 \(m\) 条带权的边,每次加入后询问是否存在一个边集,满足每个点的度数均为奇数。
若存在,则还需要最小化边集中的最大边权。
\(n \le 10^5\)\(m\le 3 \times10^5\)

所需要求转化为要求所有联通块的大小均为偶数。
按照边的权值从小到大排序。
考虑处理动态问题。
注意到一条边加入之后一段时间会被删除,我们可以试着线段树分治。但是我们不知道这条边什么时候删除。
注意答案单调不增,考虑倒着来,如果到了时刻 \(t\) 我们直接暴力往后新加边直到满足题意(显然需要满足加入时间 \(\le t\)),然后我们就知道了新加入的边的影响范围。
在线段树上边分治边覆盖即可。
\(O(n\log n\alpha (n))\)

https://codeforces.com/contest/603/submission/242675806

CF150E

给定一颗带边权的树,求一条边数在 \([L,R]\) 之间的路径,并使得路径上边权的中位数最大。输出一条可行路径的两个端点。
注:此处 \(1,2,3,4\) 的中位数为 \(3\) ,而非 \(2\) 或者 \(2.5\)
\(n\le 10^5\)

考虑点分治。
处理中位数考虑二分答案,假设我们判断 \(x\) 是否合法,我们将 \(<x\) 的设为 \(-1\),否则设为 \(1\),那么就变成找大于零长度在 \([L,R]\) 的路径。
考虑找 \([L,R]\) 的路径,直接暴力就是 \(O(n^2)\) 的,我们考虑使用单调队列,优化这个过程,但是由于初始化的缘故我们最坏需要先塞 \(R-L+1\) 个点,这样还是 \(O(n^2)\) 的。
考虑按照深度或者字树大小从小到大合并,那么每次初始化加入点的数量就不大于当前新增的点的数量,这样单次就是 \(O(n \log n)\) 了(需要排序)(不过好像换成计数排序就可以少一个 \(\log\) 但是我懒得写了)。
\(O(n\log^2n)\)(sort),\(O(n\log n)\)(计数排序)。

https://codeforces.com/contest/150/submission/242873620(sort)

CF319E

有一个区间的集合,初始为空。当 \(c<a<d\)\(c<b<d\) ,且 \((a,b),(c,d)\) 都在集合中时,你可以从区间 \((a,b)\) 移动到 \((c,d)\)。你需要支持下面的操作:

  • 1 x y,加入一个新区间 \((x,y)\)。保证加入的区间长度严格单调递增。
  • 2 a b,询问是否能从第 \(a\) 个加入的区间移动到第 \(b\) 个。
    操作数 \(1\le n\le 10^5\),保证其他任何数字都是整数且不超过 \(10^9\)

考虑一个线段看成一个点,两个线段时间能到达就连一条有向边。
那么相交的时候就是连双向边,如果包含那就是有向边(小的指向大的)。

引理:如果一个点可以到另一个点,那么一定存在一条路径,保证只有第一条边为单向边或者全部为双向边。

因此我们只保留双向边。在一个连通块中我们如果存这个连通块所有区间最左边的端点和最右边的端点,令这个区间为联通快的 代表区间

引理2:如果一个区间与一个联通块的 代表区间 相交 或者 被包含,那么这个区间可以到达这个连通块的任意一个区间。

注意到加入边的长度单调递增,所以新加入的边不可能被包含在之前的线段中。
对坐标离散化使得坐标的范围与 \(n\) 同阶。
考虑一个线段 \((a,b)\)
\([a+1,b-1]\) 这条线段加入线段树,也就是在线段树对应节点开一个 vector 把这个线段的编号扔进去。
然后我们注意到线段树上包含 \(a,b\) 的节点中的都存有与这个线段相交的区间编号。
全部合并,合并之后注意到这些点上的线段都合并到一个内去了,所以只需要保留一个,这样均摊复杂度就是正确的了。

查询直接用 引理2 即可。
\(O(n\log n)\)

https://codeforces.com/contest/319/submission/242787315

CF526F

给定一个 \(n \times n\) 的棋盘,其中有 \(n\) 个棋子,每行每列恰好有一个棋子。
对于所有的 \(1 \leq k \leq n\),求有多少个 \(k \times k\) 的子棋盘中恰好有 \(k\) 个棋子。
\(n \le 3 \times 10^5\)

超级大水题。

注意到每行每列只有一个棋子。设 \(p_x\) 为第 \(x\) 行的棋子在哪一列。
发现对于一个 \([l,r]\) 如果 \(p_l,p_{l+1},\cdots,p_{r}\) 这些数字能组成连续的区间那么选择 \([l,r]\) 行就有且仅有一种方案。
枚举右端点维护后缀 \(max-min+r-l\),只有为 \(0\) 是为一种方案,并且 \(0\) 为该式子能取的最小值,即最小值计数问题。
\(O(n\log n)\)

https://codeforces.com/contest/526/submission/242498760

posted @ 2024-01-18 20:44  jiangtaizhe001  阅读(3)  评论(0编辑  收藏  举报