差分,能够巧妙地维护多种区间修改,将区间修改转化为单点修改,将询问转化为前缀查询。
但是,差分能支持的,岂止是这些。有时,差分一下,性质多多。
例1. [Luogu P4552]IncDec Sequence
Description
给定一个序列,请求出至少需要多少次区间统加111或区间统减111的操作才能使得整个序列中的数两两相同。
为了增加难度,你也需要求出,在满足操作次数最小且最终序列中的数两两相同的前提下,最终能够得到多少种不同的序列。
Solution
本题中有区间修改这一说。不难想到差分。
现在,我们完成了一个重要的转化: 给定一个长度为n+1n+1n+1的序列,每次可以选择序列中的任两个位置,一个加111,另一个减111,使得这个序列的第2−n2-n2−n个位置均为000。
由于我们要让操作次数尽可能得小,我们要先贪心地去选择在[2,n][2,n][2,n]区间内的一个正数和一个负数并将它们配对,正数减111,负数加111。经过了这些操作之后,我们再将剩下的数去与1,n+11,n+11,n+1中的一个数配对。假设这个数为正,那么配对之后它一定要减111;否则一定要加111。经历这些操作之后,我们便完成了要求。
假设2−n2-n2−n这些数中,正数之和为xxx,负数的绝对值之和为yyy。首先,我们使用了min(x,y)min(x,y)min(x,y)次操作,每次操作将一个正数减111,一个负数加111。然后,我们使用了max(x,y)−min(x,y)max(x,y)-min(x,y)max(x,y)−min(x,y)次操作,将每一个[2,n][2,n][2,n]区间内不为000的数与下标为111或n+1n+1n+1中的一个数配对。于是我们总共使用了max(x,y)max(x,y)max(x,y)次操作。由于第一个位置有max(x,y)−min(x,y)+1max(x,y)-min(x,y)+1max(x,y)−min(x,y)+1种不同的值(即,对于剩下的max(x,y)−min(x,y)max(x,y)-min(x,y)max(x,y)−min(x,y)都可以与下标为111的位置配对或不与它配对),所以两个答案分别为:
①max(x,y)max(x,y)max(x,y)
②max(x,y)−min(x,y)+1max(x,y)-min(x,y)+1max(x,y)−min(x,y)+1
时间复杂度O(n)O(n)O(n)。本题得到完美解决。
Summary
我们通过差分,将区间修改转化为单点修改,自然而然得到了几个性质,从而推出结论。
例2. [LNOI2014]LCA
Description
给定一棵包含nnn个节点的树,qqq次询问,每次给定l,r,xl,r,xl,r,x,请你求出∑i=lrdepth(LCA(i,x))\sum_{i=l}^r depth(LCA(i,x))i=l∑rdepth(LCA(i,x))
这里的depthdepthdepth表示一个节点的深度,即其与根节点的距离加111。
Solution
一道绝妙的好题。
首先,我们考虑depth(LCA(i,x))depth(LCA(i,x))depth(LCA(i,x))等于什么。在这之前,我们先思考depthdepthdepth表示什么,以及LCALCALCA表示什么。
①depthdepthdepth: 一个节点到根节点的深度加1。
也就是说,从这个节点开始往上走,一直走到根,期间经过的点的数量。
②LCALCALCA: 两个节点的最近公共祖先。
也就是说,从这两个节点中的一个往上走,对每一个经过的点打上标记;然后另外一个节点也向上走,如果遇到了一个打上标记的节点,立即将这个节点作为它们俩的LCA。
综上所述,depth(LCA(i,x))depth(LCA(i,x))depth(LCA(i,x))就等价于: 让iii不停地往上走,对每一个走到的节点打上标记,即将该点的点权加111;然后再让xxx往上走,标记的总数量(即点权之和)就是depth(i,x)depth(i,x)depth(i,x)。
于是,∑i=lrdepth(LCA(i,x))\sum_{i=l}^r depth(LCA(i,x))∑i=lrdepth(LCA(i,x))也可以通过类似上述方法来求出。
首先,本题的询问似乎很难处理,而且询问也没有强制在线,于是我们考虑离线。同时,我们再将一个询问拆成两个询问,即查询[1,r][1,r][1,r]与[1,l−1][1,l-1][1,l−1],二者相减即可。
然后,我们对于现在的2m2m2m个询问从小到大排序。每次加入一个新节点,就将它到根节点的路径上所有节点的点权都加111;对于每一次询问,查询它到根节点路径上每个节点的点权之和。这相当于“路径修改,路径查询”,可以通过重链剖分套线段树在O(qlog2n)O(q \log^2 n)O(qlog2n)的代价下搞定。
总时间复杂度O(n+qlog2n)O(n+q \log^2 n)O(n+qlog2n)。注意取模即可。
Summary
有时,区间查询可以转化为更容易处理的前缀查询,方便我们“莫队”离线处理。同时,本题也考察了树链剖分,是一道不可多得的LNOI好题。
例3. [GXOI/GZOI2019]旧词(改编)
Description
给定一棵包含nnn个节点的树和一个常数k(1≤k≤109)k(1≤k≤10^9)k(1≤k≤109),qqq次询问,每次给定l,r,xl,r,xl,r,x,请你求出∑i=lrdepth(LCA(i,x))k\sum_{i=l}^r depth(LCA(i,x))^ki=l∑rdepth(LCA(i,x))k
这里的depthdepthdepth表示一个节点的深度,即其与根节点的距离加111。
由于答案可能很大,请将其对998244353998244353998244353取模。
Solution
我们仍然将每一个询问拆成两个,离线下来排序。但是k≠1k≠1k=1似乎很难办……而且kkk这么大,二项式定理拆开都不行……
别慌,我们考虑能不能通过一步差分,将本题转化为例2。定义Ai=(depthi+1)k−depthikA_i=(depth_{i}+1)^k-depth_{i}^kAi=(depthi+1)k−depthik,对于新加入的一个节点,从它到根节点的路径上每个节点都加上一个AiA_iAi;对于一次查询,仍然查询它到根节点的路径上所有节点的点权之和。我们可以处理出AAA的前缀和,然后通过树剖套线段树求出。
这种做法为什么是正确的呢?根据差分的性质,从一个节点到根节点的路径上求出点权之和,就是这个节点本身的贡献之一。于是,每次查询我们都能得到正确的答案。
总时间复杂度仍然为O(n+qlog2n)O(n+q \log^2 n)O(n+qlog2n)。
一些练习题
①P6070
先挖一个比较显然的性质,然后直接二分差分即可。
②[ABC155F]Perils in Parallel
一道套路题,通过差分可以转化为单点修改,然后建图乱搞即可。
③P3620
一道经典题,通过差分进行等效转化即可。
本文介绍了差分技巧在解决区间修改及区间查询问题中的应用,并通过三个具体实例详细讲解了如何利用差分技巧简化问题,包括序列统一操作计数、树上路径深度求和及其变形问题。
5098

被折叠的 条评论
为什么被折叠?



