离线问题大杂烩
离线问题综合
友链:个人主页
本文为笔记~希望能帮到您!看完就点个赞再走吧,如果可以的话教我莫队就更好了!
目录:
CSES1734 - Distinct Values Queries
给定一个数列。有 \(Q\) 个查询,每个查询给定一个区间,输出区间不同数字的个数。
值域:\(1\le x_i \le 1e9\) ,数列长度和询问个数都是 \(2e5\) 。
样例:
Input:
5
3 2 3 1 2
1 3
1 5
Output:
2
3
没有修改操作,考虑离线处理。
noip1= 大佬一秒钟想到了莫队,但实际上不用。
考虑将询问按右端点位置排序。
定义一个新数组 \(Color\) ,将每一个数在已经查询到的区间里面最右边一个设为 \(1\) 。
对于每个询问, BIT 求和即可。
细节是如何记录上一个为 \(1\) 的当前数字,也不难想, \(map\) 乱搞就好。
代码就不放了,毕竟要赶暑假作业。
CSES2416- Increasing Array Queries
给定一个序列,每个查询,输出对于一个区间,最少多少次操作才能将自区间变成非严格 \(LIS\) 。
操作:选定区间内任意一个数,加上 \(1\) 。
Input:
5 3
2 10 4 2 5
3 5
2 2
1 4
Output:
2
0
14
显而易见的 Subtask :
对于给定一个区间,如何把它通过上面那种操作变成非严格 \(LIS\) ?
其实很简单,\(O(n)\) dp 就好。
可以用分块等方法优化到根号。(我不会)
正解:
从右往左扫序列。当扫到点 \(P\) 时,对于每个点 \(i,P\le i \le n\) 维护一个值:\(maxx_i\) ,定义如下:
当在当前扫到的点 \(P\) 左边新加入一个点时,我们如何维护已经扫过的点的 \(maxx\) 值?
其实更新时 \(maxx\) 值更改的部分是从 \(P\) 开始往右连续的一段区间。
结合一个例子:
点 \(P\) 的定义和刚刚一样, \(P\) 往后的就是已经扫到的,现在考虑 \(P\) 前面新增的点 \(P-1\) :
| \(i\) | P-1 | P | P+1 | P+2 | P+3 | P+4 | P+5 | P+6 | P+7 |
|---|---|---|---|---|---|---|---|---|---|
| \(a_i\) | 5 | 3 | 2 | 2 | 2 | 1 | 5 | 4 | 6 |
| \(maxx_i\) | --- | 3 | 3 | 3 | 3 | 3 | 5 | 5 | 6 |
| 更新后: | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 6 |
我们发现新增了点 \(5\) 之后,只更改了 \(P\) 到 \(P+4\) 的 \(maxx\) 值。
由于 \(maxx\) 数组是单调的,考虑二分。
我们最后求的区间 \([l,r]\) 的答案就是当扫描到 \(l\) 时,
所以用 sgt 维护。在二分更改时同时更改懒标记,可以实现 \(O(logn)\) 的复杂度修改(暴力是对数平方)。
询问也是一只 \(\log\) ,可以通过本题。
Problem - 1132G - Codeforces
定义最长贪心子序列:选了一个数就必须选第一个比它大的数。
给定一个数 \(k\) ,按顺序求出每一个长度为 \(k\) 的连续自区间最长贪心子序列的长度。
序列长度 \(n\le 1e6\) 。
sample-in:
6 4
1 5 2 5 3 6
sample-out
2 2 3
解释:
-
序列1: (1,5,2,5) 选择 (1,5)或者(2,5) 均可。
-
序列2: (5,2,5,3) 选择 (2,5)。
-
序列3: (2,5,3,6) 选择 (2,5,6)。
思路:
先预处理出每个数选择之后必须选的下一个数(这个是固定的):叫作 \(next\) 数组。
每个结点的后继唯一,可以当做一条链。
对于已经当前区间,把每个点 \(i\) 和 \(next_i\) 连一条边,那么就可以构造出一棵树。
原问题化成一个区间最长链问题,即在树中找一条深度最长的链。
有点像 Cartessian 树?我也觉得 /kk 。
建树:
先把每个点的 \(dfn\) 和 \(siz\) 预处理出来。
树上维护要使用树剖(长链剖分),我不会,考虑一种化简为繁的方法:sgt
通过 \(dfn\) 序把树拍到一个序列上(跟 Tarjan 求 \(\text{LCA}\) 一样),通过线段树区间修改。
考虑新增点和删除点。
新增点 \(a[x]\) : 就把以结点 \(x\) 为根的子树的最长链上的每个结点的大小 \(+1\) 。区间修改板子。
删除点,有两种办法:
本质一样,我用的是方法 \(1\) 。
实现:
不难写,读者能耐心读到这里,一定有一定的代码能力,自己切了吧~~
备注:
等我学会了长链剖分,回来补代码。
Problem - 319E - Codeforces
洛谷评分 \(NOI/NOI+/CTSC\) , \(Codeforces 3000+\) 的难题。
有一个区间的集合,设为 \(S\) , 初始为空。
注意:本题中区间左闭右开。
如果对于区间 (a,b) 和 (c,d) ,满足:
- 区间有交集,即 \(c<a<d\) 或 \(b<c<d\) 。
- 区间都在集合中出现,即 \((a,b)\in S \And (c,d)\in S\)
您就可以从区间 (a,b) 走到 (c,d)。
操作:
- 1 x y,加入一个新区间 (x,y)。保证加入的区间长度严格单调递增。
- 2 a b,询问是否能从第 a 个加入的区间移动到第 b 个。
定义:
定义一个区块指一些区间的并集。
即:只要一些点在一个区块内,这些点互相可达。
结论:
设一开始有区块 \(J\) ,现在新增一个区间 \(I\) 。
Lemma α :如果 \(I \cup J \neq \emptyset\) ,下证 \(I\) 与 \(J\) 内任意集合可达。
考虑 \(J\) 内上一个区间 \(I_0\) ,根据性质 \(|I_0|\le|I|\) 可以证明上结论。(手玩一下)?
Lemma β :和上面差不多,如果与 \(I\) 有交集的区块有 \(J_1,J_2,J_3,\ldots,J_k\) , 那么这些区块和 \(I\) 可以形成一个新区块。
证明和上面差不多,考虑归纳法。读者自证不难。
可以发现,这些区块具有嵌套性。
如何实现?
先维护这些区块(起点,终点)。
每次新增区间(a,b) 时,找到所有属于区块且覆盖 \(a\) 和 \(b\) 的区间,删掉这些区间,把新区间加进去就好了。
考虑询问,如何判断 \(I_a\) 区间属不属于区块 \(J\) ?
对于以上两种操作,如何用 \(DS\) 维护?
\(DS\) 太难了,我只会 \(DSU\) 。
可爱的并查姬~
还有个小细节,我们对于一个区间 \(x\) ,如何判断 \(x\) 在哪个区块中?
先把端点离散化,然后用线段树维护查询就好了。
大致流程:
用并查姬维护连通块,离散化后用线段树维护每个区块,把一个区间拆分成 \(\log n\) 个线段树结点。
每加入一条边,就把它左右端点对应在线段树中的节点到根节点的路径合并掉,修改 \(lazytag\) 。
询问:判断属不属于一个并查姬。
时间复杂度:
每次操作在线段树上 \(update\) ,时间复杂度 \(\log n\) ,操作同时合并并查集,时间复杂度 \(\log n\) 。
询问时判断是不是在一个 \(\text{dsu}\) 中,复杂度 \(\log n\) 。
综上,时间复杂度为 \(O(n\log^2n)\) 。
F - Wide Swap (AGC001)
第一场 \(AGC\) 的题,洛谷黑题。
给出一个元素集合为 {\(1,2,\dots,n\)} \((1\leq N\leq 500,000)\) 的排列 \(P\) ,当有 \(i,j (1\leq i<j\leq N)\)满足 $j-i\ge K $ 且 $ |P_{i}-P_{j}|=1$ 时,可以交换 $P_i $ 和 \(P_j\) 。
求:可能排列中字典序最小的排列。
我们称置换是从 \(i\) 到 \(P_i\) 的映射成为置换 \(T\) 。
考虑逆置换 \(T^{-1}\) 表示从 \(P_i\) 到 \(i\) 的映射。
考虑一组样例:
\(A=[1,2,3,4,5]\)
\(P=[4,3,1,2,5]\)
经过置换 \(Q\) 之后,\(A_1=[4,3,1,2,5]\) ;
再做一下逆置换, \(A_2=[1,2,3,4,5]\)
(废话)
讲解完逆置换之后,我们考虑在逆置换的意义下解决本题。
将原问题转换为等价问题:
对于逆置换后的数组 \(Q\) (其实 \(Q=P\)) ,原问题转化为:如果 \(Q_{x+1}-Q_{x}\le K\) \((1\le x < N)\)
那么可以交换 \((Q_{x+1},Q_{x})\) 。
让操作后 \(Q\) 数组的字典序最小。

浙公网安备 33010602011771号