Ynoi

2004

E. rpmtdq

also Tree Distance from The 2022 ICPC Jinan Regional Contest

树,边有边权,\(q\) 次询问,求编号在 \((l,r)\) 内的点的任意两点的最小距离

对于最近点对问题,通用思路是寻找支配点对,也就是说有很多的点对是没用的,我们可以扔掉。

路径查询问题,我们使用点分治。假设当前的子树的重心为 \(rt\)\(d_p\) 表示 \(p\)\(rt\) 的距离,我们将 \(dis(i,j)\) 看作 \(d_i+d_j\),因为如果当前选中了两个同一子树内的那递归到它们的时候答案肯定更小,否则肯定没用,于是对于 \(i<j<k\),如果 \((i,k)\) 是有效的,\((i,j)\)\((j,k)\) 都是无效的那么 \(d_i+d_k<d_i+d_j,d_i+d_k<d_k+d_j\)\(\max(d_i,d_k)<d_j\),也就是说 \((i,j)\) 有效等价于 \(\max(d_i,d_j)<\min_{k=i+1}^{j-1}\{d_k\}\),这启发我们维护单调栈,每次将 \(p\) 和栈顶看作一个支配点对,这样支配点对个数是 \(O(\sum siz\log siz)=O(n\log n)\) 的。

考虑知道了支配点对之后怎么做。扫描线,对于支配点对 \([l,r]\) 我们把贡献挂到左端点上,对 \(l\) 原来的贡献和 \(dis(l,r)\)\(\min\) 作为新的贡献,询问 \([l,r]\) 的贡献就是在这里面的 \(l\) 的贡献的最小值,也就是说我们要维护单点取 \(\min\) 和后缀 \(\min\),用树状数组维护即可。

code

2011

A. 初始化

序列,操作 \(x,y,z\)\(y\) 开始每隔 \(x\) 个的数加上 \(z\),查询区间和。\(n\leq 200000\),时间限制为 500ms。

这样的操作对答案的影响很难快速合并,也没有好的性质,没法用分治数据结构维护,所以考虑根号做法,这里使用根号分治。设定阈值 \(B\),对于 \(x\geq B\) 暴力修改,对于 \(x\leq B\) 维护膜 \(B\)\(x\) 的数的前缀与后缀和,查询的时候把这几部分拼起来就行了,零 \(B=\sqrt n\) 可以达到理论最有时间复杂度,但众所周知实操的时候要调,实现中我令 \(B=128\),并且由于本题卡死的时限我使用手动膜科技,具体见代码。code

C. 成都七中

一棵树,树上每个点有颜色,每次询问给出 \(l, r, x\) 表示查询编号在 \(l,r\) 的点所构成的点集中 \(x\) 所在的连通块的颜色数。\(n\leq 10^5\)

看见这种不关心树的具体形态的且不能在树上直接做的问题直接上点分树。对一次查询 \(l,r,x\),找到 \(x\) 的祖先中深度最浅的满足与 \(x\) 路径中编号 \(\max\leq r,\min\geq l\) 的点 \(fa\),可以发现所求联通块一定在 \(fa\) 在点分树上的子树中。于是把询问放在 \(fa\) 上。处理完之后枚举树上的点,问题转化为平面上数颜色问题,维护每个节点到 \(fa\) 的距离最大值和最小值 \((x,y)\),把 \((x,y)\) 扔到平面直角坐标系中,发现所求是右下角一段区域,于是从下往上扫描线,然后只需要考虑每种颜色出现的最右的位置,用树状数组维护,时间复杂度 \(O(n\log n)\)

2016

D. 炸脖龙 I

序列,操作为对区间 \([l\dots r]\)\(x\),查询区间 \([l\dots r]\),回答

\[a[l]^{a[l+1]^{a[l+2]^{\dots ^{a[r]}}}} \bmod p \]

设要求的东西为 \(f(l,r)\),发现 \(f(l,r)\not=f(l,k)^{f(k+1,r)}\),于是线段树和分块豆似了。这下只能去发现一些性质。

由扩展欧拉定理,我们将 \(f(l,r)\) 转化为 \(a_l^{f(l+1,r)\bmod \varphi(p)+[f(l+1,r)>\varphi(p)]\varphi(p)}\),于是可以递归求 \(f(l+1,r)\bmod \varphi(p)\)。考虑 \(p\rightarrow \varphi(p)\) 的变换最多多少次变为 \(1\),容易猜到次数是 \(O(\log V)\) 次的,下面是证明。

\(p=\prod_{i=1}^k p_i^{\alpha_i}\),有 \(\varphi(p)=\prod_{i=1}^k(p_i-1)=p\prod_{i=1}^k\frac{p_i-1}{p_i}\),考虑若 \(p\bmod 2=1\),那么 \(\prod\) 中定有 \(\frac{1}{2}\),否则 \(\prod\) 中最大的也小于 \(\frac{1}{2}\),于是变换次数是 \(O(\log V)\) 的。证毕。

于是暴力,\(\varphi(p)\) 变到 1 直接停,但还是想想细节。陶似乎是不可避免的,而导致此题困难的正是对于 \(f(l+1,r)>\varphi(p)\) 的陶,如果 \(\exists i,a_i=1\),那么要求的问题就不是 \(f(l,r)\) 而是 \(f(l,i)\),否则 \(\forall x\in [l\dots r]\) 必然有 \(a_x\geq 2\),发现最多 5 次 \(f\) 就大于 \(\varphi(p)\) 了,于是只要判断区间长度大于 5 并且没有一个 1 就可以规避掉陶。实操的时候考虑到点 \(i\),只要考虑 \([i+1\dotsi+6]\) 这一段就可以了。code

2017

由乃打扑克

区间加区间第 \(k\) 小,\(n,m\leq 10^5\)

分块,对于每块维护块内序与加的 tag,查询的时候二分第 \(k\) 大的值即可。

2019

先说一下这些题是怎么想到分块的。

首先,这种查询区间问题的东西,肯定得找个数据结构维护。

然后这三个题维护的信息都不满足幺半群性质,更别提什么双半群结构,所以只能用分块。

强制在线求排列区间逆序对

贡献了五页提交哈哈哈哈哈哈。再也不 #define int long long 了。

对每个块内排序,预处理整块与整块之间的答案 \(F_{i,j}\),预处理 [st[pos[i]],i][i,ed[pos[i]]] 的贡献,记为 \(pre_i\)\(suf_i\)

对于同一块内的情况,答案是 \(pre_{r}-pre_{l-1}\),再减去多算的横跨 \([L,l-1]\)\([l,r]\) 之间的情况数。

对于不在同一块内的情况,整块与整块之间的答案已经求出,两个散块对答案的贡献是 \(suf_l+pre_r\) 加上两端区间归并排序起来的答案。

考虑如何 \(O(\sqrt n)\) 计算散块与整块对答案的贡献。

我们希望求出单点与块的贡献之和,直接做时空超了,考虑在这两维中挑选一位做前缀和,对于块做前缀和效果甚微,于是对单点做前缀和。

预处理 \(c_{i,j}\) 表示前 \(i\) 个数与第 \(j\) 块产生的贡献,于是散块与整块对答案的贡献就可以用前缀和的思想相减从而求出答案。

不强制在线求区间逆序对

考虑暴力莫队就是在值域上维护值的出现次数,每次扫端点的时候更新,时间复杂度 \(O(n\sqrt m \log n)\),并不优。

考虑优化,假设当前做了一次指针右移,那么相当于查询 \([l\dots r]\)\(\geq a_r\) 的数量,那么差分一下,问题转化为 \([1\dots r]\)\(\geq a_r\) 的数量减去 \([1\dots l)\)\(\geq a_r\) 的数量。前面一部分易于在 \(O(n\log n)\) 的时间内处理,后面一部分的形式容易想到再次莫队。考虑在 \(l\) 上把所有 \(r\) 记下来,然后扫 \(l\),只需要做到 \(O(\sqrt n)\) 修改,\(O(1)\) 查询就可以满足 \(O(n\sqrt m)\) 的数据量了,发现值域分块正好可以。我们维护值域内的前缀和与值域快之间的前缀和,就可以满足需求了,时间复杂度 \(O(n\sqrt m+n\sqrt n)\),但是记下来 \(O(n\sqrt m)\) 的修改还是太超标了,但是注意到满足条件的右端点是连续的,所以完全可以只存两端点,这样空间复杂度就是 \(O(n)\) 的了。

强制在线求区间众数的出现次数

一个类似的题目是[Violet]蒲公英,在这个题中,我们用 vector 对每个数维护出现位置的集合,然后分块做。这道题我们思路类似,提前预处理块与块之间的答案,然后从内往外扫散块,如果当前位置的值可以使 \(ans\leftarrow ans+1\),那么更新答案,否则跳过。

posted @ 2025-05-15 17:08  lhc0707  阅读(12)  评论(0)    收藏  举报